diff options
Diffstat (limited to 'drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c')
-rwxr-xr-x | drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c b/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c new file mode 100755 index 00000000..08fc6069 --- /dev/null +++ b/drivers/input/touchscreen/ft6x0x/ft6x06_ex_fun.c @@ -0,0 +1,1021 @@ +/* + *drivers/input/touchscreen/ft5x06_ex_fun.c + * + *FocalTech ft6x06 expand function for debug. + * + *Copyright (c) 2010 Focal tech Ltd. + * + *This software is licensed under the terms of the GNU General Public + *License version 2, as published by the Free Software Foundation, and + *may be copied, distributed, and modified under those terms. + * + *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. + * + *Note:the error code of EIO is the general error in this file. + */ + + +#include "ft6x06_ex_fun.h" +#include "ft6x06_ts.h" + +#include <linux/mount.h> +#include <linux/netdevice.h> +#include <linux/proc_fs.h> + +struct Upgrade_Info { + u16 delay_aa; /*delay of write FT_UPGRADE_AA */ + u16 delay_55; /*delay of write FT_UPGRADE_55 */ + u8 upgrade_id_1; /*upgrade id 1 */ + u8 upgrade_id_2; /*upgrade id 2 */ + u16 delay_readid; /*delay of read id */ + u16 delay_earse_flash; /*delay of earse flash*/ +}; + + +int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, + u32 dw_lenth); + +static unsigned char CTPM_FW[] = { + #include "FT5406.i" +}; + +static struct mutex g_device_mutex; + +int ft6x06_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue) +{ + unsigned char buf[2] = {0}; + buf[0] = regaddr; + buf[1] = regvalue; + + return ft6x06_i2c_Write(client, buf, sizeof(buf)); +} + + +int ft6x06_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue) +{ + return ft6x06_i2c_Read(client, ®addr, 1, regvalue, 1); +} + + +int fts_ctpm_auto_clb(struct i2c_client *client) +{ + unsigned char uc_temp = 0x00; + unsigned char i = 0; + + /*start auto CLB */ + msleep(200); + + ft6x06_write_reg(client, 0, FTS_FACTORYMODE_VALUE); + /*make sure already enter factory mode */ + msleep(100); + /*write command to start calibration */ + ft6x06_write_reg(client, 2, 0x4); + msleep(300); + for (i = 0; i < 100; i++) { + ft6x06_read_reg(client, 0, &uc_temp); + /*return to normal mode, calibration finish */ + if (0x0 == ((uc_temp & 0x70) >> 4)) + break; + } + + msleep(200); + /*calibration OK */ + msleep(300); + ft6x06_write_reg(client, 0, FTS_FACTORYMODE_VALUE); /*goto factory mode for store */ + msleep(100); /*make sure already enter factory mode */ + ft6x06_write_reg(client, 2, 0x5); /*store CLB result */ + msleep(300); + ft6x06_write_reg(client, 0, FTS_WORKMODE_VALUE); /*return to normal mode */ + msleep(300); + + /*store CLB result OK */ + return 0; +} + +/* +upgrade with *.i file +*/ +int fts_ctpm_fw_upgrade_with_i_file(struct i2c_client *client) +{ + u8 *pbt_buf = NULL; + int i_ret; + int fw_len = sizeof(CTPM_FW); + + /*judge the fw that will be upgraded + * if illegal, then stop upgrade and return. + */ + + if (fw_len < 8 || fw_len > 32 * 1024) { + dev_err(&client->dev, "%s:FW length error\n", __func__); + return -EIO; + } + + /*FW upgrade */ + pbt_buf = CTPM_FW; + /*call the upgrade function */ + + i_ret = fts_ctpm_fw_upgrade(client, pbt_buf, sizeof(CTPM_FW)); + if (i_ret != 0) + dev_err(&client->dev, "%s:upgrade failed. err.\n", + __func__); + + return i_ret; +} + +u8 fts_ctpm_get_i_file_ver(void) +{ + u16 ui_sz; + ui_sz = sizeof(CTPM_FW); + if (ui_sz > 2) + return CTPM_FW[0x10a]; + + return 0x00; /*default value */ +} + +/*update project setting +*only update these settings for COB project, or for some special case +*/ +int fts_ctpm_update_project_setting(struct i2c_client *client) +{ + u8 uc_i2c_addr; /*I2C slave address (7 bit address)*/ + u8 uc_io_voltage; /*IO Voltage 0---3.3v; 1----1.8v*/ + u8 uc_panel_factory_id; /*TP panel factory ID*/ + u8 buf[FTS_SETTING_BUF_LEN]; + u8 reg_val[2] = {0}; + u8 auc_i2c_write_buf[10] = {0}; + u8 packet_buf[FTS_SETTING_BUF_LEN + 6]; + u32 i = 0; + int i_ret; + + uc_i2c_addr = client->addr; + uc_io_voltage = 0x0; + uc_panel_factory_id = 0x5a; + + + /*Step 1:Reset CTPM + *write 0xaa to register 0xfc + */ + ft6x06_write_reg(client, 0xfc, 0xaa); + msleep(50); + + /*write 0x55 to register 0xfc */ + ft6x06_write_reg(client, 0xfc, 0x55); + msleep(30); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = 0x55; + auc_i2c_write_buf[1] = 0xaa; + do { + i++; + i_ret = ft6x06_i2c_Write(client, auc_i2c_write_buf, 2); + msleep(5); + } while (i_ret <= 0 && i < 5); + + + /*********Step 3:check READ-ID***********************/ + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = + 0x00; + + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + + if (reg_val[0] == 0x79 && reg_val[1] == 0x3) + dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + else + return -EIO; + + auc_i2c_write_buf[0] = 0xcd; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + dev_dbg(&client->dev, "bootloader version = 0x%x\n", reg_val[0]); + + /*--------- read current project setting ---------- */ + /*set read start address */ + buf[0] = 0x3; + buf[1] = 0x0; + buf[2] = 0x78; + buf[3] = 0x0; + + ft6x06_i2c_Read(client, buf, 4, buf, FTS_SETTING_BUF_LEN); + dev_dbg(&client->dev, "[FTS] old setting: uc_i2c_addr = 0x%x,\ + uc_io_voltage = %d, uc_panel_factory_id = 0x%x\n", + buf[0], buf[2], buf[4]); + + /*--------- Step 4:erase project setting --------------*/ + auc_i2c_write_buf[0] = 0x63; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(100); + + /*---------- Set new settings ---------------*/ + buf[0] = uc_i2c_addr; + buf[1] = ~uc_i2c_addr; + buf[2] = uc_io_voltage; + buf[3] = ~uc_io_voltage; + buf[4] = uc_panel_factory_id; + buf[5] = ~uc_panel_factory_id; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + packet_buf[2] = 0x78; + packet_buf[3] = 0x0; + packet_buf[4] = 0; + packet_buf[5] = FTS_SETTING_BUF_LEN; + + for (i = 0; i < FTS_SETTING_BUF_LEN; i++) + packet_buf[6 + i] = buf[i]; + + ft6x06_i2c_Write(client, packet_buf, FTS_SETTING_BUF_LEN + 6); + msleep(100); + + /********* reset the new FW***********************/ + auc_i2c_write_buf[0] = 0x07; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + + msleep(200); + return 0; +} + +int fts_ctpm_auto_upgrade(struct i2c_client *client) +{ + u8 uc_host_fm_ver = FT6x06_REG_FW_VER; + u8 uc_tp_fm_ver; + int i_ret; + + ft6x06_read_reg(client, FT6x06_REG_FW_VER, &uc_tp_fm_ver); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + + if (/*the firmware in touch panel maybe corrupted */ + uc_tp_fm_ver == FT6x06_REG_FW_VER || + /*the firmware in host flash is new, need upgrade */ + uc_tp_fm_ver < uc_host_fm_ver + ) { + msleep(100); + dev_dbg(&client->dev, "[FTS] uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x\n", + uc_tp_fm_ver, uc_host_fm_ver); + i_ret = fts_ctpm_fw_upgrade_with_i_file(client); + if (i_ret == 0) { + msleep(300); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + dev_dbg(&client->dev, "[FTS] upgrade to new version 0x%x\n", + uc_host_fm_ver); + } else { + pr_err("[FTS] upgrade failed ret=%d.\n", i_ret); + return -EIO; + } + } + + return 0; +} + +void delay_qt_ms(unsigned long w_ms) +{ + unsigned long i; + unsigned long j; + + for (i = 0; i < w_ms; i++) + { + for (j = 0; j < 1000; j++) + { + udelay(1); + } + } +} + +int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, + u32 dw_lenth) +{ + u8 reg_val[2] = {0}; + u32 i = 0; + u32 packet_number; + u32 j; + u32 temp; + u32 lenght; + u32 fw_length; + u8 packet_buf[FTS_PACKET_LENGTH + 6]; + u8 auc_i2c_write_buf[10]; + u8 bt_ecc; + int i_ret; + + + if(pbt_buf[0] != 0x02) + { + DBG("[FTS] FW first byte is not 0x02. so it is invalid \n"); + return -1; + } + + if(dw_lenth > 0x11f) + { + fw_length = ((u32)pbt_buf[0x100]<<8) + pbt_buf[0x101]; + if(dw_lenth < fw_length) + { + DBG("[FTS] Fw length is invalid \n"); + return -1; + } + } + else + { + DBG("[FTS] Fw length is invalid \n"); + return -1; + } + + //DBG("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", reg_val[0], reg_val[1]); + + for (i = 0; i < FTS_UPGRADE_LOOP; i++) { + /*********Step 1:Reset CTPM *****/ + /*write 0xaa to register 0xbc */ + + ft6x06_write_reg(client, 0xbc, FT_UPGRADE_AA); + msleep(FT6X06_UPGRADE_AA_DELAY); + + /*write 0x55 to register 0xbc */ + ft6x06_write_reg(client, 0xbc, FT_UPGRADE_55); + + msleep(FT6X06_UPGRADE_55_DELAY); + + /*********Step 2:Enter upgrade mode *****/ + auc_i2c_write_buf[0] = FT_UPGRADE_55; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + + auc_i2c_write_buf[0] = FT_UPGRADE_AA; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(FT6X06_UPGRADE_READID_DELAY); + + /*********Step 3:check READ-ID***********************/ + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] = + 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + + + if (reg_val[0] == FT6X06_UPGRADE_ID_1 + && reg_val[1] == FT6X06_UPGRADE_ID_2) { + //dev_dbg(&client->dev, "[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n", + //reg_val[0], reg_val[1]); + DBG("[FTS] Step 3: GET CTPM ID OK,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + break; + } else { + dev_err(&client->dev, "[FTS] Step 3: GET CTPM ID FAIL,ID1 = 0x%x,ID2 = 0x%x\n", + reg_val[0], reg_val[1]); + } + } + if (i >= FTS_UPGRADE_LOOP) + return -EIO; + + auc_i2c_write_buf[0] = 0x90; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + auc_i2c_write_buf[4] = 0x00; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 5); + + //auc_i2c_write_buf[0] = 0xcd; + //ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + + + /*Step 4:erase app and panel paramenter area*/ + DBG("Step 4:erase app and panel paramenter area\n"); + auc_i2c_write_buf[0] = 0x61; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); /*erase app area */ + msleep(FT6X06_UPGRADE_EARSE_DELAY); + + for(i = 0;i < 200;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == reg_val[0] && 0x02 == reg_val[1]) + { + DBG("[FTS] erase app finished \n"); + break; + } + msleep(50); + } + + /*********Step 5:write firmware(FW) to ctpm flash*********/ + bt_ecc = 0; + DBG("Step 5:write firmware(FW) to ctpm flash\n"); + + dw_lenth = fw_length; + packet_number = (dw_lenth) / FTS_PACKET_LENGTH; + packet_buf[0] = 0xbf; + packet_buf[1] = 0x00; + + for (j = 0; j < packet_number; j++) { + temp = j * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + lenght = FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (lenght >> 8); + packet_buf[5] = (u8) lenght; + + for (i = 0; i < FTS_PACKET_LENGTH; i++) { + packet_buf[6 + i] = pbt_buf[j * FTS_PACKET_LENGTH + i]; + bt_ecc ^= packet_buf[6 + i]; + } + + ft6x06_i2c_Write(client, packet_buf, FTS_PACKET_LENGTH + 6); + + for(i = 0;i < 30;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) == (((reg_val[0] & 0x0f) << 8) |reg_val[1])) + { + DBG("[FTS] write a block data finished \n"); + break; + } + msleep(1); + } + //msleep(FTS_PACKET_LENGTH / 6 + 1); + //DBG("write bytes:0x%04x\n", (j+1) * FTS_PACKET_LENGTH); + //delay_qt_ms(FTS_PACKET_LENGTH / 6 + 1); + } + + if ((dw_lenth) % FTS_PACKET_LENGTH > 0) { + temp = packet_number * FTS_PACKET_LENGTH; + packet_buf[2] = (u8) (temp >> 8); + packet_buf[3] = (u8) temp; + temp = (dw_lenth) % FTS_PACKET_LENGTH; + packet_buf[4] = (u8) (temp >> 8); + packet_buf[5] = (u8) temp; + + for (i = 0; i < temp; i++) { + packet_buf[6 + i] = pbt_buf[packet_number * FTS_PACKET_LENGTH + i]; + bt_ecc ^= packet_buf[6 + i]; + } + + ft6x06_i2c_Write(client, packet_buf, temp + 6); + + for(i = 0;i < 30;i++) + { + auc_i2c_write_buf[0] = 0x6a; + auc_i2c_write_buf[1] = 0x00; + auc_i2c_write_buf[2] = 0x00; + auc_i2c_write_buf[3] = 0x00; + reg_val[0] = 0x00; + reg_val[1] = 0x00; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); + if(0xb0 == (reg_val[0] & 0xf0) && (0x03 + (j % 0x0ffd)) == (((reg_val[0] & 0x0f) << 8) |reg_val[1])) + { + DBG("[FTS] write a block data finished \n"); + break; + } + msleep(1); + } + //msleep(20); + } + + + /*********Step 6: read out checksum***********************/ + /*send the opration head */ + DBG("Step 6: read out checksum\n"); + auc_i2c_write_buf[0] = 0xcc; + ft6x06_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); + if (reg_val[0] != bt_ecc) { + dev_err(&client->dev, "[FTS]--ecc error! FW=%02x bt_ecc=%02x\n", + reg_val[0], + bt_ecc); + return -EIO; + } + + /*********Step 7: reset the new FW***********************/ + DBG("Step 7: reset the new FW\n"); + auc_i2c_write_buf[0] = 0x07; + ft6x06_i2c_Write(client, auc_i2c_write_buf, 1); + msleep(300); /*make sure CTP startup normally */ + + return 0; +} + +/*sysfs debug*/ + +/* +*get firmware size + +@firmware_name:firmware name +*note:the firmware default path is sdcard. + if you want to change the dir, please modify by yourself. +*/ +static int ft6x06_GetFirmwareSize(char *firmware_name) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize = 0; + char filepath[128]; + memset(filepath, 0, sizeof(filepath)); + + sprintf(filepath, "/sdcard/%s", firmware_name); + + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + filp_close(pfile, NULL); + return fsize; +} + + + +/* +*read firmware buf for .bin file. + +@firmware_name: fireware name +@firmware_buf: data buf of fireware + +note:the firmware default path is sdcard. + if you want to change the dir, please modify by yourself. +*/ +static int ft6x06_ReadFirmware(char *firmware_name, + unsigned char *firmware_buf) +{ + struct file *pfile = NULL; + struct inode *inode; + unsigned long magic; + off_t fsize; + char filepath[128]; + loff_t pos; + mm_segment_t old_fs; + + memset(filepath, 0, sizeof(filepath)); + sprintf(filepath, "/sdcard/%s", firmware_name); + if (NULL == pfile) + pfile = filp_open(filepath, O_RDONLY, 0); + if (IS_ERR(pfile)) { + pr_err("error occured while opening file %s.\n", filepath); + return -EIO; + } + + inode = pfile->f_dentry->d_inode; + magic = inode->i_sb->s_magic; + fsize = inode->i_size; + old_fs = get_fs(); + set_fs(KERNEL_DS); + pos = 0; + vfs_read(pfile, firmware_buf, fsize, &pos); + filp_close(pfile, NULL); + set_fs(old_fs); + + return 0; +} + + + +/* +upgrade with *.bin file +*/ + +int fts_ctpm_fw_upgrade_with_app_file(struct i2c_client *client, + char *firmware_name) +{ + u8 *pbt_buf = NULL; + int i_ret; + int fwsize = ft6x06_GetFirmwareSize(firmware_name); + + if (fwsize <= 0) { + dev_err(&client->dev, "%s ERROR:Get firmware size failed\n", + __func__); + return -EIO; + } + + if (fwsize < 8 || fwsize > 32 * 1024) { + dev_dbg(&client->dev, "%s:FW length error\n", __func__); + return -EIO; + } + + /*=========FW upgrade========================*/ + pbt_buf = kmalloc(fwsize + 1, GFP_ATOMIC); + + if (ft6x06_ReadFirmware(firmware_name, pbt_buf)) { + dev_err(&client->dev, "%s() - ERROR: request_firmware failed\n", + __func__); + kfree(pbt_buf); + return -EIO; + } + + /*call the upgrade function */ + i_ret = fts_ctpm_fw_upgrade(client, pbt_buf, fwsize); + if (i_ret != 0) + dev_err(&client->dev, "%s() - ERROR:[FTS] upgrade failed..\n", + __func__); + //else + //fts_ctpm_auto_clb(client); + kfree(pbt_buf); + + return i_ret; +} + +static ssize_t ft6x06_tpfwver_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t num_read_chars = 0; + u8 fwver = 0; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + mutex_lock(&g_device_mutex); + + if (ft6x06_read_reg(client, FT6x06_REG_FW_VER, &fwver) < 0) + num_read_chars = snprintf(buf, PAGE_SIZE, + "get tp fw version fail!\n"); + else + num_read_chars = snprintf(buf, PAGE_SIZE, "%02X\n", fwver); + + mutex_unlock(&g_device_mutex); + + return num_read_chars; +} + +static ssize_t ft6x06_tpfwver_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + /*place holder for future use*/ + return -EPERM; +} + + + +static ssize_t ft6x06_tprwreg_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /*place holder for future use*/ + return -EPERM; +} + +static ssize_t ft6x06_tprwreg_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + ssize_t num_read_chars = 0; + int retval; + long unsigned int wmreg = 0; + u8 regaddr = 0xff, regvalue = 0xff; + u8 valbuf[5] = {0}; + + memset(valbuf, 0, sizeof(valbuf)); + mutex_lock(&g_device_mutex); + num_read_chars = count - 1; + + if (num_read_chars != 2) { + if (num_read_chars != 4) { + pr_info("please input 2 or 4 character\n"); + goto error_return; + } + } + + memcpy(valbuf, buf, num_read_chars); + retval = strict_strtoul(valbuf, 16, &wmreg); + + if (0 != retval) { + dev_err(&client->dev, "%s() - ERROR: Could not convert the "\ + "given input to a number." \ + "The given input was: \"%s\"\n", + __func__, buf); + goto error_return; + } + + if (2 == num_read_chars) { + /*read register*/ + regaddr = wmreg; + if (ft6x06_read_reg(client, regaddr, ®value) < 0) + dev_err(&client->dev, "Could not read the register(0x%02x)\n", + regaddr); + else + pr_info("the register(0x%02x) is 0x%02x\n", + regaddr, regvalue); + } else { + regaddr = wmreg >> 8; + regvalue = wmreg; + if (ft6x06_write_reg(client, regaddr, regvalue) < 0) + dev_err(&client->dev, "Could not write the register(0x%02x)\n", + regaddr); + else + dev_err(&client->dev, "Write 0x%02x into register(0x%02x) successful\n", + regvalue, regaddr); + } + +error_return: + mutex_unlock(&g_device_mutex); + + return count; +} + +static ssize_t ft6x06_fwupdate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /* place holder for future use */ + return -EPERM; +} + +/*upgrade from *.i*/ +static ssize_t ft6x06_fwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ft6x06_ts_data *data = NULL; + u8 uc_host_fm_ver; + int i_ret; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + data = (struct ft6x06_ts_data *)i2c_get_clientdata(client); + + mutex_lock(&g_device_mutex); + + disable_irq(client->irq); + i_ret = fts_ctpm_fw_upgrade_with_i_file(client); + if (i_ret == 0) { + msleep(300); + uc_host_fm_ver = fts_ctpm_get_i_file_ver(); + pr_info("%s [FTS] upgrade to new version 0x%x\n", __func__, + uc_host_fm_ver); + } else + dev_err(&client->dev, "%s ERROR:[FTS] upgrade failed.\n", + __func__); + + enable_irq(client->irq); + mutex_unlock(&g_device_mutex); + + return count; +} + +static ssize_t ft6x06_fwupgradeapp_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + /*place holder for future use*/ + return -EPERM; +} + + +/*upgrade from app.bin*/ +static ssize_t ft6x06_fwupgradeapp_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char fwname[128]; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + + memset(fwname, 0, sizeof(fwname)); + sprintf(fwname, "%s", buf); + fwname[count - 1] = '\0'; + + mutex_lock(&g_device_mutex); + disable_irq(client->irq); + + fts_ctpm_fw_upgrade_with_app_file(client, fwname); + + enable_irq(client->irq); + mutex_unlock(&g_device_mutex); + + return count; +} + + +/*sysfs */ +/*get the fw version +*example:cat ftstpfwver +*/ +static DEVICE_ATTR(ftstpfwver, S_IRUGO | S_IWUSR, ft6x06_tpfwver_show, + ft6x06_tpfwver_store); + +/*upgrade from *.i +*example: echo 1 > ftsfwupdate +*/ +static DEVICE_ATTR(ftsfwupdate, S_IRUGO | S_IWUSR, ft6x06_fwupdate_show, + ft6x06_fwupdate_store); + +/*read and write register +*read example: echo 88 > ftstprwreg ---read register 0x88 +*write example:echo 8807 > ftstprwreg ---write 0x07 into register 0x88 +* +*note:the number of input must be 2 or 4.if it not enough,please fill in the 0. +*/ +static DEVICE_ATTR(ftstprwreg, S_IRUGO | S_IWUSR, ft6x06_tprwreg_show, + ft6x06_tprwreg_store); + + +/*upgrade from app.bin +*example:echo "*_app.bin" > ftsfwupgradeapp +*/ +static DEVICE_ATTR(ftsfwupgradeapp, S_IRUGO | S_IWUSR, ft6x06_fwupgradeapp_show, + ft6x06_fwupgradeapp_store); + + +/*add your attr in here*/ +static struct attribute *ft6x06_attributes[] = { + &dev_attr_ftstpfwver.attr, + &dev_attr_ftsfwupdate.attr, + &dev_attr_ftstprwreg.attr, + &dev_attr_ftsfwupgradeapp.attr, + NULL +}; + +static struct attribute_group ft6x06_attribute_group = { + .attrs = ft6x06_attributes +}; + +/*create sysfs for debug*/ +int ft6x06_create_sysfs(struct i2c_client *client) +{ + int err; + err = sysfs_create_group(&client->dev.kobj, &ft6x06_attribute_group); + if (0 != err) { + dev_err(&client->dev, + "%s() - ERROR: sysfs_create_group() failed.\n", + __func__); + sysfs_remove_group(&client->dev.kobj, &ft6x06_attribute_group); + return -EIO; + } else { + mutex_init(&g_device_mutex); + pr_info("ft6x06:%s() - sysfs_create_group() succeeded.\n", + __func__); + } + return err; +} + +void ft6x06_release_sysfs(struct i2c_client *client) +{ + sysfs_remove_group(&client->dev.kobj, &ft6x06_attribute_group); + mutex_destroy(&g_device_mutex); +} + +/*create apk debug channel*/ +#define PROC_UPGRADE 0 +#define PROC_READ_REGISTER 1 +#define PROC_WRITE_REGISTER 2 +#define PROC_AUTOCLB 4 +#define PROC_UPGRADE_INFO 5 +#define PROC_WRITE_DATA 6 +#define PROC_READ_DATA 7 + + +#define PROC_NAME "ft5x0x-debug" +static unsigned char proc_operate_mode = PROC_UPGRADE; +static struct proc_dir_entry *ft6x06_proc_entry; +/*interface of write proc*/ +static int ft6x06_debug_write(struct file *filp, + const char __user *buff, unsigned long len, void *data) +{ + struct i2c_client *client = (struct i2c_client *)ft6x06_proc_entry->data; + unsigned char writebuf[FTS_PACKET_LENGTH]; + int buflen = len; + int writelen = 0; + int ret = 0; + + if (copy_from_user(&writebuf, buff, buflen)) { + dev_err(&client->dev, "%s:copy from user error\n", __func__); + return -EFAULT; + } + proc_operate_mode = writebuf[0]; + + switch (proc_operate_mode) { + case PROC_UPGRADE: + { + char upgrade_file_path[128]; + memset(upgrade_file_path, 0, sizeof(upgrade_file_path)); + sprintf(upgrade_file_path, "%s", writebuf + 1); + upgrade_file_path[buflen-1] = '\0'; + DBG("%s\n", upgrade_file_path); + disable_irq(client->irq); + + ret = fts_ctpm_fw_upgrade_with_app_file(client, upgrade_file_path); + + enable_irq(client->irq); + if (ret < 0) { + dev_err(&client->dev, "%s:upgrade failed.\n", __func__); + return ret; + } + } + break; + case PROC_READ_REGISTER: + writelen = 1; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + case PROC_WRITE_REGISTER: + writelen = 2; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + case PROC_AUTOCLB: + DBG("%s: autoclb\n", __func__); + fts_ctpm_auto_clb(client); + break; + case PROC_READ_DATA: + case PROC_WRITE_DATA: + writelen = len - 1; + ret = ft6x06_i2c_Write(client, writebuf + 1, writelen); + if (ret < 0) { + dev_err(&client->dev, "%s:write iic error\n", __func__); + return ret; + } + break; + default: + break; + } + + + return len; +} + +/*interface of read proc*/ +static int ft6x06_debug_read( char *page, char **start, + off_t off, int count, int *eof, void *data ) +{ + struct i2c_client *client = (struct i2c_client *)ft6x06_proc_entry->data; + int ret = 0; + unsigned char buf[PAGE_SIZE]; + int num_read_chars = 0; + int readlen = 0; + u8 regvalue = 0x00, regaddr = 0x00; + + switch (proc_operate_mode) { + case PROC_UPGRADE: + /*after calling ft5x0x_debug_write to upgrade*/ + regaddr = 0xA6; + ret = ft6x06_read_reg(client, regaddr, ®value); + if (ret < 0) + num_read_chars = sprintf(buf, "%s", "get fw version failed.\n"); + else + num_read_chars = sprintf(buf, "current fw version:0x%02x\n", regvalue); + break; + case PROC_READ_REGISTER: + readlen = 1; + ret = ft6x06_i2c_Read(client, NULL, 0, buf, readlen); + if (ret < 0) { + dev_err(&client->dev, "%s:read iic error\n", __func__); + return ret; + } + num_read_chars = 1; + break; + case PROC_READ_DATA: + readlen = count; + ret = ft6x06_i2c_Read(client, NULL, 0, buf, readlen); + if (ret < 0) { + dev_err(&client->dev, "%s:read iic error\n", __func__); + return ret; + } + + num_read_chars = readlen; + break; + case PROC_WRITE_DATA: + break; + default: + break; + } + + memcpy(page, buf, num_read_chars); + return num_read_chars; +} +int ft6x06_create_apk_debug_channel(struct i2c_client * client) +{ + ft6x06_proc_entry = create_proc_entry(PROC_NAME, 0777, NULL); + if (NULL == ft6x06_proc_entry) { + dev_err(&client->dev, "Couldn't create proc entry!\n"); + return -ENOMEM; + } else { + dev_info(&client->dev, "Create proc entry success!\n"); + ft6x06_proc_entry->data = client; + ft6x06_proc_entry->write_proc = ft6x06_debug_write; + ft6x06_proc_entry->read_proc = ft6x06_debug_read; + } + return 0; +} + +void ft6x06_release_apk_debug_channel(void) +{ + if (ft6x06_proc_entry) + remove_proc_entry(PROC_NAME, NULL); +} + |