/* *drivers/input/touchscreen/ft5x06_ex_fun.c * *FocalTech IC driver 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 "tpd.h" #include "tpd_custom_ft5206.h" #ifdef TPD_AUTO_UPGRADE #include "focaltech_ex_fun.h" #include #include //#include #include extern u8 *I2CDMABuf_va; extern dma_addr_t I2CDMABuf_pa; static struct Upgrade_Info fts_updateinfo_curr = TPD_FT_UPDATE_INFO; int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, u32 dw_lenth); static unsigned char CTPM_FW[] = { #include TPD_FT_UPDATE_FW_NAME }; /* *fts_i2c_Read-read data and write data by i2c *@client: handle of i2c *@writebuf: Data that will be written to the slave *@writelen: How many bytes to write *@readbuf: Where to store data read from slave *@readlen: How many bytes to read * *Returns negative errno, else the number of messages executed * * */ int fts_i2c_Read(struct i2c_client *client, char *writebuf, int writelen, char *readbuf, int readlen) { int ret=0,i=0; #if 0//for normal I2c transfer if (writelen > 0) { struct i2c_msg msgs[] = { { .addr = client->addr, .flags = 0, .len = writelen, .buf = writebuf, }, { .addr = client->addr, .flags = I2C_M_RD, .len = readlen, .buf = readbuf, }, }; ret = i2c_transfer(client->adapter, msgs, 2); if (ret < 0) dev_err(&client->dev, "f%s: i2c read error.\n", __func__); } else { struct i2c_msg msgs[] = { { .addr = client->addr, .flags = I2C_M_RD, .len = readlen, .buf = readbuf, }, }; ret = i2c_transfer(client->adapter, msgs, 1); if (ret < 0) dev_err(&client->dev, "%s:i2c read error.\n", __func__); } #else// for DMA I2c transfer if(writelen!=0) { //DMA Write if(0)//if(writelen < 8 ) { //MSE_ERR("Sensor non-dma write timing is %x!\r\n", this_client->timing); ret= i2c_master_send(client, writebuf, writelen); } else { for(i = 0 ; i < writelen; i++) { I2CDMABuf_va[i] = writebuf[i]; } client->addr = (client->addr & I2C_MASK_FLAG) | I2C_DMA_FLAG; if((ret=i2c_master_send(client, (unsigned char *)I2CDMABuf_pa, writelen))!=writelen) dev_err(&client->dev, "###%s i2c write len=%x,buffaddr=%x\n", __func__,ret,I2CDMABuf_pa); //MSE_ERR("Sensor dma timing is %x!\r\n", this_client->timing); //return ret; client->addr = client->addr & I2C_MASK_FLAG &(~ I2C_DMA_FLAG); } } //DMA Read if(readlen!=0) { if(0)//if (readlen <8) { { ret = i2c_master_recv(client, (unsigned char *)readbuf, readlen); } else { client->addr = (client->addr & I2C_MASK_FLAG) | I2C_DMA_FLAG; ret = i2c_master_recv(client, (unsigned char *)I2CDMABuf_pa, readlen); for(i = 0; i < readlen; i++) { readbuf[i] = I2CDMABuf_va[i]; } client->addr = client->addr & I2C_MASK_FLAG &(~ I2C_DMA_FLAG); } } #endif return ret; } /*write data by i2c*/ int fts_i2c_Write(struct i2c_client *client, char *writebuf, int writelen) { int ret; int i = 0; //printk("fts_i2c_Write %d %x %x %x %x",writelen,writebuf,I2CDMABuf_va,I2CDMABuf_pa,client); client->addr = client->addr & I2C_MASK_FLAG; // client->ext_flag |= I2C_DIRECTION_FLAG; // client->timing = 100; #if 0 struct i2c_msg msg[] = { { .addr = client->addr, .flags = 0, .len = writelen, .buf = writebuf, }, }; ret = i2c_transfer(client->adapter, msg, 1); if (ret < 0) dev_err(&client->dev, "%s i2c write error.\n", __func__); #else if(0)//if(writelen < 8) { //MSE_ERR("Sensor non-dma write timing is %x!\r\n", this_client->timing); ret = i2c_master_send(client, writebuf, writelen); } else { for(i = 0 ; i < writelen; i++) { I2CDMABuf_va[i] = writebuf[i]; } client->addr = (client->addr & I2C_MASK_FLAG) | I2C_DMA_FLAG; if((ret=i2c_master_send(client, (unsigned char *)I2CDMABuf_pa, writelen))!=writelen) dev_err(&client->dev, "###%s i2c write len=%x,buffaddr=%x\n", __func__,ret,I2CDMABuf_pa); //MSE_ERR("Sensor dma timing is %x!\r\n", this_client->timing); client->addr = client->addr & I2C_MASK_FLAG &(~ I2C_DMA_FLAG); } #endif return ret; } int fts_write_reg(struct i2c_client *client, u8 regaddr, u8 regvalue) { unsigned char buf[2] = {0}; buf[0] = regaddr; buf[1] = regvalue; return fts_i2c_Write(client, buf, sizeof(buf)); } int fts_read_reg(struct i2c_client *client, u8 regaddr, u8 *regvalue) { return fts_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); fts_write_reg(client, 0, FTS_FACTORYMODE_VALUE); /*make sure already enter factory mode */ msleep(100); /*write command to start calibration */ fts_write_reg(client, 2, 0x4); msleep(300); if ((fts_updateinfo_curr.CHIP_ID==0x11) ||(fts_updateinfo_curr.CHIP_ID==0x12) ||(fts_updateinfo_curr.CHIP_ID==0x13) ||(fts_updateinfo_curr.CHIP_ID==0x14)) //5x36,5x36i { for(i=0;i<100;i++) { fts_read_reg(client, 0x02, &uc_temp); if (0x02 == uc_temp || 0xFF == uc_temp) { /*if 0x02, then auto clb ok, else 0xff, auto clb failure*/ break; } msleep(20); } } else { for(i=0;i<100;i++) { fts_read_reg(client, 0, &uc_temp); if (0x0 == ((uc_temp&0x70)>>4)) /*return to normal mode, calibration finish*/ { break; } msleep(20); } } /*calibration OK*/ fts_write_reg(client, 0, 0x40); /*goto factory mode for store*/ msleep(200); /*make sure already enter factory mode*/ fts_write_reg(client, 2, 0x5); /*store CLB result*/ msleep(300); fts_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; } if ((CTPM_FW[fw_len - 8] ^ CTPM_FW[fw_len - 6]) == 0xFF && (CTPM_FW[fw_len - 7] ^ CTPM_FW[fw_len - 5]) == 0xFF && (CTPM_FW[fw_len - 3] ^ CTPM_FW[fw_len - 4]) == 0xFF) { /*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__); else if(fts_updateinfo_curr.AUTO_CLB==AUTO_CLB_NEED) fts_ctpm_auto_clb(client); /*start auto CLB */ } else { dev_err(&client->dev, "%s:FW format error\n", __func__); return -EBADFD; } 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[ui_sz - 2]; return 0x00; /*default value */ } #if 0 /*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 */ fts_write_reg(client, 0xfc, 0xaa); msleep(50); /*write 0x55 to register 0xfc */ fts_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 = fts_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; fts_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; fts_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; fts_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; fts_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]; fts_i2c_Write(client, packet_buf, FTS_SETTING_BUF_LEN + 6); msleep(100); /********* reset the new FW***********************/ auc_i2c_write_buf[0] = 0x07; fts_i2c_Write(client, auc_i2c_write_buf, 1); msleep(200); return 0; } #endif int fts_ctpm_auto_upgrade(struct i2c_client *client) { u8 uc_host_fm_ver = FT_REG_FW_VER; u8 uc_tp_fm_ver; int i_ret; fts_read_reg(client, FT_REG_FW_VER, &uc_tp_fm_ver); uc_host_fm_ver = fts_ctpm_get_i_file_ver(); printk("[FTS] uc_tp_fm_ver = 0x%x, uc_host_fm_ver = 0x%x\n",uc_tp_fm_ver, uc_host_fm_ver); if (/*the firmware in touch panel maybe corrupted */ uc_tp_fm_ver == FT_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); printk("[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; } int fts_ctpm_fw_upgrade(struct i2c_client *client, u8 *pbt_buf, u32 dw_lenth) { u8 reg_val[2] = {0}; u32 i = 0; u8 is_5336_new_bootloader = 0; u32 packet_number; u32 j=0; u32 temp; u32 lenght; u8 packet_buf[FTS_PACKET_LENGTH + 6]; u8 auc_i2c_write_buf[10]; u8 bt_ecc; //int i_ret; // struct Upgrade_Info upgradeinfo; //fts_get_upgrade_info(&upgradeinfo); for (i = 0; i < FTS_UPGRADE_LOOP; i++) { msleep(100); printk("[FTS] Step 1:Reset CTPM\n"); /*********Step 1:Reset CTPM *****/ /*write 0xaa to register 0xfc */ //if (DEVICE_IC_TYPE == IC_FT6208 || DEVICE_IC_TYPE == IC_FT6x06) if(fts_updateinfo_curr.CHIP_ID==0x05 || fts_updateinfo_curr.CHIP_ID==0x06 ) fts_write_reg(client, 0xbc, FT_UPGRADE_AA); else fts_write_reg(client, 0xfc, FT_UPGRADE_AA); msleep(fts_updateinfo_curr.delay_aa); /*write 0x55 to register 0xfc */ //if(DEVICE_IC_TYPE == IC_FT6208 || DEVICE_IC_TYPE == IC_FT6x06) if(fts_updateinfo_curr.CHIP_ID==0x05 || fts_updateinfo_curr.CHIP_ID==0x06 ) fts_write_reg(client, 0xbc, FT_UPGRADE_55); else fts_write_reg(client, 0xfc, FT_UPGRADE_55); if(i<=15) { msleep(fts_updateinfo_curr.delay_55+i*3); } else { msleep(fts_updateinfo_curr.delay_55-(i-15)*2); } /*********Step 2:Enter upgrade mode *****/ printk("[FTS] Step 2:Enter upgrade mode \n"); #if 0 auc_i2c_write_buf[0] = FT_UPGRADE_55; auc_i2c_write_buf[1] = FT_UPGRADE_AA; do { j++; i_ret = fts_i2c_Write(client, auc_i2c_write_buf, 2); msleep(5); } while (i_ret <= 0 && j < 5); #else auc_i2c_write_buf[0] = FT_UPGRADE_55; fts_i2c_Write(client, auc_i2c_write_buf, 1); msleep(5); auc_i2c_write_buf[0] = FT_UPGRADE_AA; fts_i2c_Write(client, auc_i2c_write_buf, 1); #endif #if 1 /*********Step 3:check READ-ID***********************/ msleep(fts_updateinfo_curr.delay_readid); auc_i2c_write_buf[0] = 0x90; auc_i2c_write_buf[1] = auc_i2c_write_buf[2] = auc_i2c_write_buf[3] =0x00; fts_i2c_Read(client, auc_i2c_write_buf, 4, reg_val, 2); printk("[FTS] Step 3: CTPM ID,ID1 = 0x%x,ID2 = 0x%x\n",reg_val[0], reg_val[1]); printk("[FTS] Step 3: fts_updateinfo_curr,ID1 = 0x%x,ID2 = 0x%x\n", fts_updateinfo_curr.upgrade_id_1, fts_updateinfo_curr.upgrade_id_2); if (reg_val[0] == fts_updateinfo_curr.upgrade_id_1 && reg_val[1] == fts_updateinfo_curr.upgrade_id_2) { break; } else { } #endif } if (i >= FTS_UPGRADE_LOOP) return -EIO; auc_i2c_write_buf[0] = 0xcd; fts_i2c_Read(client, auc_i2c_write_buf, 1, reg_val, 1); if (reg_val[0] > 4) is_5336_new_bootloader = 1; printk("[FTS] Step 4:erase app and panel paramenter area\n"); /*Step 4:erase app and panel paramenter area*/ auc_i2c_write_buf[0] = 0x61; fts_i2c_Write(client, auc_i2c_write_buf, 1); /*erase app area */ msleep(fts_updateinfo_curr.delay_earse_flash); /*erase panel parameter area */ auc_i2c_write_buf[0] = 0x63; fts_i2c_Write(client, auc_i2c_write_buf, 1); msleep(100); printk("[FTS] Step 5:write firmware(FW) to ctpm flash\n"); /*********Step 5:write firmware(FW) to ctpm flash*********/ bt_ecc = 0; dw_lenth = dw_lenth - 8; 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]; } fts_i2c_Write(client, packet_buf, FTS_PACKET_LENGTH + 6); msleep(FTS_PACKET_LENGTH / 6 + 1); if((((j+1) * FTS_PACKET_LENGTH)%1024)==0) 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]; } fts_i2c_Write(client, packet_buf, temp + 6); msleep(20); } /*send the last six byte*/ for (i = 0; i<6; i++) { if (is_5336_new_bootloader && ((fts_updateinfo_curr.CHIP_ID==0x11) ||(fts_updateinfo_curr.CHIP_ID==0x12) ||(fts_updateinfo_curr.CHIP_ID==0x13) ||(fts_updateinfo_curr.CHIP_ID==0x14)))//5x36,5x36i temp = 0x7bfa + i; else temp = 0x6ffa + i; packet_buf[2] = (u8)(temp>>8); packet_buf[3] = (u8)temp; temp =1; packet_buf[4] = (u8)(temp>>8); packet_buf[5] = (u8)temp; packet_buf[6] = pbt_buf[ dw_lenth + i]; bt_ecc ^= packet_buf[6]; fts_i2c_Write(client, packet_buf, 7); msleep(20); } printk("[FTS] Step 6: read out checksum\n"); /*********Step 6: read out checksum***********************/ /*send the opration head */ auc_i2c_write_buf[0] = 0xcc; fts_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; } printk("[FTS] Step 7: reset the new FW\n"); /*********Step 7: reset the new FW***********************/ auc_i2c_write_buf[0] = 0x07; fts_i2c_Write(client, auc_i2c_write_buf, 1); msleep(300); /*make sure CTP startup normally */ return 0; } #ifdef TPD_SYSFS_DEBUG static DEFINE_MUTEX(g_device_mutex); /*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 fts_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, "%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 fts_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, "%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=0; int fwsize = fts_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 (fts_ReadFirmware(firmware_name, pbt_buf)) { dev_err(&client->dev, "%s() - ERROR: request_firmware failed\n", __func__); kfree(pbt_buf); //return -EIO; i_ret = -EIO; goto err_ret; } /*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 if(fts_updateinfo_curr.AUTO_CLB==AUTO_CLB_NEED) fts_ctpm_auto_clb(client); err_ret: kfree(pbt_buf); return i_ret; } static ssize_t fts_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 (fts_read_reg(client, FT_REG_FW_VER, &fwver) < 0) num_read_chars = snprintf(buf, FTS_PAGE_SIZE, "get tp fw version fail!\n"); else num_read_chars = snprintf(buf, FTS_PAGE_SIZE, "%02X\n", fwver); mutex_unlock(&g_device_mutex); return num_read_chars; } static ssize_t fts_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 fts_tprwreg_show(struct device *dev, struct device_attribute *attr, char *buf) { /*place holder for future use*/ return -EPERM; } static ssize_t fts_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 (fts_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 (fts_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 fts_fwupdate_show(struct device *dev, struct device_attribute *attr, char *buf) { /* place holder for future use */ return -EPERM; } /*upgrade from *.i*/ static ssize_t fts_fwupdate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fts_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 fts_ts_data *)i2c_get_clientdata(client); mutex_lock(&g_device_mutex); //disable_irq(client->irq); mt_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); 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); mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); mutex_unlock(&g_device_mutex); return count; } static ssize_t fts_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 fts_fwupgradeapp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { ssize_t num_read_chars = 0; 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); mt_eint_mask(CUST_EINT_TOUCH_PANEL_NUM); if(0==fts_ctpm_fw_upgrade_with_app_file(client, fwname)) { num_read_chars = snprintf(buf, FTS_PAGE_SIZE, "FTP firmware upgrade success!\n"); } else { num_read_chars = snprintf(buf, FTS_PAGE_SIZE, "FTP firmware upgrade fail!\n"); } //enable_irq(client->irq); mt_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM); mutex_unlock(&g_device_mutex); return num_read_chars; } /*sysfs */ /*get the fw version *example:cat ftstpfwver */ static DEVICE_ATTR(ftstpfwver, S_IRUGO | S_IWUSR, fts_tpfwver_show, fts_tpfwver_store); /*upgrade from *.i *example: echo 1 > ftsfwupdate */ static DEVICE_ATTR(ftsfwupdate, S_IRUGO | S_IWUSR, fts_fwupdate_show, fts_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, fts_tprwreg_show, fts_tprwreg_store); /*upgrade from app.bin *example:echo "*_app.bin" > ftsfwupgradeapp */ static DEVICE_ATTR(ftsfwupgradeapp, S_IRUGO | S_IWUSR, fts_fwupgradeapp_show, fts_fwupgradeapp_store); /*add your attr in here*/ static struct attribute *fts_attributes[] = { &dev_attr_ftstpfwver.attr, &dev_attr_ftsfwupdate.attr, &dev_attr_ftstprwreg.attr, &dev_attr_ftsfwupgradeapp.attr, NULL }; static struct attribute_group fts_attribute_group = { .attrs = fts_attributes }; /*create sysfs for debug*/ int fts_create_sysfs(struct i2c_client *client) { int err; I2CDMABuf_va = (u8 *)dma_alloc_coherent(NULL, FTS_DMA_BUF_SIZE, (dma_addr_t *)I2CDMABuf_pa, GFP_KERNEL); if(!I2CDMABuf_va) { dev_dbg(&client->dev,"%s Allocate DMA I2C Buffer failed!\n",__func__); return -EIO; } //printk("FTP: I2CDMABuf_pa=%x,val=%x val2=%x\n",&I2CDMABuf_pa,I2CDMABuf_pa,(unsigned char *)I2CDMABuf_pa); err = sysfs_create_group(&client->dev.kobj, &fts_attribute_group); if (0 != err) { dev_err(&client->dev, "%s() - ERROR: sysfs_create_group() failed.\n", __func__); sysfs_remove_group(&client->dev.kobj, &fts_attribute_group); return -EIO; } else { mutex_init(&g_device_mutex); pr_info("ft6x06:%s() - sysfs_create_group() succeeded.\n", __func__); } return err; } void fts_release_sysfs(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &fts_attribute_group); mutex_destroy(&g_device_mutex); if(I2CDMABuf_va) { dma_free_coherent(NULL, FTS_DMA_BUF_SIZE, I2CDMABuf_va, I2CDMABuf_pa); I2CDMABuf_va = NULL; I2CDMABuf_pa = 0; } } /*create apk debug channel*/ #define PROC_UPGRADE 0 #define PROC_READ_REGISTER 1 #define PROC_WRITE_REGISTER 2 #define PROC_RAWDATA 3 #define PROC_AUTOCLB 4 #define PROC_NAME "ft5x0x-debug" static unsigned char proc_operate_mode = PROC_RAWDATA; static struct proc_dir_entry *ft5x0x_proc_entry; /*interface of write proc*/ static int ft5x0x_debug_write(struct file *filp, const char __user *buff, unsigned long len, void *data) { struct i2c_client *client = (struct i2c_client *)ft5x0x_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; DBG("%s:register addr=0x%02x\n", __func__, writebuf[1]); ret = fts_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 = fts_i2c_Write(client, writebuf + 1, writelen); if (ret < 0) { dev_err(&client->dev, "%s:write iic error\n", __func__); return ret; } break; case PROC_RAWDATA: break; case PROC_AUTOCLB: fts_ctpm_auto_clb(client); break; default: break; } return len; } /*interface of read proc*/ static int ft5x0x_debug_read( char *page, char **start, off_t off, int count, int *eof, void *data ) { struct i2c_client *client = (struct i2c_client *)ft5x0x_proc_entry->data; int ret = 0, err = 0; u8 tx = 0, rx = 0; int i, j; unsigned char buf[FTS_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 = fts_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 = fts_i2c_Read(client, NULL, 0, buf, readlen); if (ret < 0) { dev_err(&client->dev, "%s:read iic error\n", __func__); return ret; } else DBG("%s:value=0x%02x\n", __func__, buf[0]); num_read_chars = 1; break; case PROC_RAWDATA: break; default: break; } memcpy(page, buf, num_read_chars); return num_read_chars; } int ft5x0x_create_apk_debug_channel(struct i2c_client * client) { ft5x0x_proc_entry = create_proc_entry(PROC_NAME, 0664, NULL); if (NULL == ft5x0x_proc_entry) { dev_err(&client->dev, "Couldn't create proc entry!\n"); return -ENOMEM; } else { dev_info(&client->dev, "Create proc entry success!\n"); ft5x0x_proc_entry->data = client; ft5x0x_proc_entry->write_proc = ft5x0x_debug_write; ft5x0x_proc_entry->read_proc = ft5x0x_debug_read; } return 0; } void ft5x0x_release_apk_debug_channel(void) { if (ft5x0x_proc_entry) remove_proc_entry(PROC_NAME, NULL); } #endif #endif