Linux的芯片驱动firmware自动升级之二:MELFAS的TP升级实例

        以MELFAS的MS6000芯片固件升级实例,说明一般的数组格式的IMAGE文件烧录的过程。该芯片需要PIN脚组合完成一定的时序并实现一组命令码进入烧录模式,并且在烧录模式下的I2C地址是0XFA(跟芯片正常工作时的地址0X40不同),在烧录完毕后进行复位并开始相应正常的TP操作。芯片大致的烧录了流程图如下:

         

实现代码如下:

(1)基础宏定义

#define FIAMWARE_NAME 	"MELFAS_W105.h"    					//数组格式IMAGE的名字
static unsigned char MS6000CTPM_FW[] =						//以数组划分空间存储烧录映象
{
	#include FIAMWARE_NAME
};
#define MS6000_ADDR_MODULE_REVISION					0x98
#define MS6000_ADDR_FIRMWARE_VERSION					0x9C		//烧录IMAGE中对应的特定字节地址
#define MS6000_TRANSFER_LENGTH						64	//一次烧录的packet字节数

/*ISP command*/
#define MS6000_ISP_CMD_ERASE					0x02
#define MS6000_ISP_CMD_ERASE_TIMING					0x0F
#define MS6000_ISP_CMD_PROGRAM_FLASH					0x03
#define MS6000_ISP_CMD_READ_FLASH					0x04
#define MS6000_ISP_CMD_PROGRAM_TIMING				0x0F
#define MS6000_ISP_CMD_READ_INFORMATION				0x06
#define MS6000_ISP_CMD_RESET							0x07

#define MS6000_7BIT_DOWNLOAD_ADDR					0x7D		
#define MS6000_8BIT_DOWNLOAD_ADDR					(MS6000_7BIT_DOWNLOAD_ADDR<<1) //linux的i2Cclient需8位地址	
#define MS6000_I2C_SLAVE_READY_STATUS				0x55

// MCS6000's responses
#define MS6000_ISP_ACK_ERASE_DONE					0x82
#define MS6000_ISP_ACK_PREPARE_ERASE_DONE			0x8F
#define MS6000_I2C_ACK_PREPARE_PROGRAM				0x8F
#define MS6000_MDS_ACK_PROGRAM_FLASH					0x83
#define MS6000_MDS_ACK_READ_FLASH					0x84
#define MS6000_MDS_ACK_PROGRAM_INFORMATION			0x88
#define MS6000_MDS_ACK_PROGRAM_LOCKED				0xFE
#define MS6000_MDS_ACK_READ_LOCKED					0xFE
#define MS6000_MDS_ACK_FAIL							0xFE

#define MS6000_ISP_ERASE_TIMING_VALUE_0				0x01
#define MS6000_ISP_ERASE_TIMING_VALUE_1				0xD4
#define MS6000_ISP_ERASE_TIMING_VALUE_2				0xC0

#define MS6000_ISP_PROGRAM_TIMING_VALUE_0			0x00
#define MS6000_ISP_PROGRAM_TIMING_VALUE_1			0x00
#define MS6000_ISP_PROGRAM_TIMING_VALUE_2			0x78

(2)I2C烧写和读TP FLASH的函数
       注意:该芯片在烧录模式下的单字节读操作和写操作都不需要寄存器地址,只send芯片地址就行。里面用到的i2c_client->address已变换地址。

static bool mfs_i2c_write_single_byte(unsigned char bufVal)
{
	int ret;
	unsigned char buf;
	buf = bufVal;

	ret = i2c_master_send(i2c_client, &buf, 1);
	if(ret <= 0){
        		printk("mfs_i2c_write_single_byte error line = %d, ret = %d\n", __LINE__, ret);
        		return false;
    	}
	return true;
}
static bool mfs_i2c_read_single_byte(unsigned char *buf)
{
	int ret;
	ret = i2c_master_recv(i2c_client, buf, 1);
	if(ret <= 0){
        		printk("mfs_i2c_read_single_byte error line = %d, ret = %d\n", __LINE__, ret);
        		return false;
    	}
	return true;
}
static int mfs_i2c_read_flash(unsigned char *pBuffer,UINT16 nAddr_start,unsigned char cLength)
{								//将nAddr_start开始的cLength个字节读到pBuffer所指的空间中
	int nRet = MS6000_RET_READ_FLASH_FAILED,i;
	BOOL bRet;
	unsigned char cmd[4],ucTemp;

// Send Read Flash command   [ Read code - address high - address low - size ]	
	cmd[0] = MS6000_ISP_CMD_READ_FLASH;
	cmd[1] = (UINT8)((nAddr_start >> 8 ) & 0xFF);
	cmd[2] = (UINT8)((nAddr_start      ) & 0xFF);
	cmd[3] = cLength;

	for(i=0;i<4;i++){
		bRet = mfs_i2c_write_single_byte(cmd[i]);
		udelay(15);
		if(bRet == FALSE)
			goto MS6000_I2C_READ_FLASH_FINISH;
	}
// Read 'Result of command'
	bRet = mfs_i2c_read_single_byte(&ucTemp);
	if( !bRet || ucTemp != MS6000_MDS_ACK_READ_FLASH){
		goto MS6000_I2C_READ_FLASH_FINISH;
	}
// Read Data  [ pCmd[3] == Size ]
	for(i=0; i<(int)cmd[3]; i++){
		udelay(100);
		bRet = mfs_i2c_read_single_byte(pBuffer++);
		if( bRet == FALSE && i!=(int)(cmd[3]-1) )
			goto MS6000_I2C_READ_FLASH_FINISH;
	}
	nRet = MS6000_RET_SUCCESS;
	
MS6000_I2C_READ_FLASH_FINISH:
	return nRet;
}

(3)进入download功能 

static void ms6000_write_download_mode_signal(void)					//通过RESET脚和EINT脚发出一组组合电平
{
	int i;
	unsigned char enter_code[14] = { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1 };

	for(i=0; i<14; i++){
		if(enter_code[i]){
			mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);	
			mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ONE);
		}
		else{
			mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);	
			mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ZERO);
		}
		mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ONE);
		udelay(15);
		mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ZERO);

		mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);	
		mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ZERO);
		udelay(100);
	}
	mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ONE);
	udelay(100);
	mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ONE);
	mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);	
}
static int ms6000_enter_download_mode(void)
{
	bool bRet;
	int nRet = MS6000_RET_ENTER_DOWNLOAD_MODE_FAILED;

	unsigned char cData=0;

	hwPowerDown(MT65XX_POWER_LDO_VGP2, "TP");	//TKEY_VDD_SET_LOW();    

	mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_GPIO);
	mt_set_gpio_dir(GPIO_I2C0_SCA_PIN, GPIO_DIR_OUT);
	mt_set_gpio_out(GPIO_I2C0_SCA_PIN, GPIO_OUT_ZERO);	
	mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_GPIO);
	mt_set_gpio_dir(GPIO_I2C0_SDA_PIN, GPIO_DIR_OUT);
	mt_set_gpio_out(GPIO_I2C0_SDA_PIN, GPIO_OUT_ZERO);		//I2C变GPIO功能

	mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_GPIO);
	mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_OUT);			//TKEY_INTR_SET_OUTPUT();
	mt_set_gpio_out(GPIO_CTP_EINT_PIN, GPIO_OUT_ZERO);		//TKEY_INTR_SET_LOW();

	mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO);
    	mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT);		//TKEY_RESETB_SET_OUTPUT();
    	mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ZERO);		//若干功能脚均需完成电平拉低的作用	

	mdelay(90);		//Delay for Stable VDD

	hwPowerOn(MT65XX_POWER_LDO_VGP2, VOL_2800, "TP");	//TKEY_VDD_SET_HIGH();
	mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE);		//TKEY_CE_SET_HIGH();
	mt_set_gpio_out(GPIO_I2C0_SDA_PIN, GPIO_OUT_ONE);		//TKEY_I2C_SDA_SET_HIGH();
	mdelay(25);

	ms6000_write_download_mode_signal();					//写命令码
	mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_SCL);
	mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_SDA);      //使能I2C的PIN脚恢复I2C功能
	mdelay(2);
	bRet = mfs_i2c_read_single_byte(&cData);
	if( bRet != TRUE || cData != MS6000_I2C_SLAVE_READY_STATUS ){
		goto MS6000_ENTER_DOWNLOAD_MODE_FINISH;
	}
	else
		printk("respond from download mode commande is 0x55 \r\n");   //只有芯片状态返回0x55,才说明进入DOWNLOAD模式
	nRet = MS6000_RET_SUCCESS;	//Entering MDS ISP mode finished.

MS6000_ENTER_DOWNLOAD_MODE_FINISH:
	return nRet;
}

(4)芯片复位和TP FLASH擦除

static void ms6000_reset_command(void)					//不管是升级过程失败还是成功,最后都需要复位并使能芯片
{
	unsigned char buf;
	mdelay(1);
	buf = MS6000_ISP_CMD_RESET;
	if(mfs_i2c_write_single_byte(buf) == true)
		printk("mfs6000_reset_command reset success \r\n");
	mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT);
	mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN);
	mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_ENABLE);
	mt_set_gpio_pull_select(GPIO_CTP_EINT_PIN, GPIO_PULL_UP);			//恢复EINT的pin功能
	mdelay(180);
}
static unsigned char ms6000_GetLibVer(void)						//取得新固件中的版本号,以便比较
{
	 unsigned int sz;
    	sz = sizeof(MS6000CTPM_FW);

    	if(sz > 2){
        		return (MS6000CTPM_FW[157]-0x30);					//版本号字节数据
    	}
    	else{
        		return 0xff;
    	}
}
static int ms6000_i2c_prepare_erase_flash(void)
{
	int   nRet = MS6000_RET_PREPARE_ERASE_FLASH_FAILED,i;
	BOOL bRet;

	UINT8 i2c_buffer[4] = {	MS6000_ISP_CMD_ERASE_TIMING,
	                        MS6000_ISP_ERASE_TIMING_VALUE_0,
	                        MS6000_ISP_ERASE_TIMING_VALUE_1,
	                        MS6000_ISP_ERASE_TIMING_VALUE_2   };
	UINT8	ucTemp;
// Send Erase Setting code
	for(i=0; i<4; i++){
		bRet = mfs_i2c_write_single_byte(i2c_buffer[i]);
		if( !bRet ){
			goto MS6000_I2C_PREPARE_ERASE_FLASH_FINISH;
		}
		udelay(15);
   	}
// Read Result
	udelay(500);
	bRet = mfs_i2c_read_single_byte(&ucTemp);
	if( bRet && ucTemp == MS6000_ISP_ACK_PREPARE_ERASE_DONE ){
		nRet = MS6000_RET_SUCCESS;
	}

MS6000_I2C_PREPARE_ERASE_FLASH_FINISH:
	return nRet;
}
static int ms6000_i2c_erase_flash(void)
{
	int   nRet = MS6000_RET_ERASE_FLASH_FAILED,i;
	BOOL bRet;
	UINT8 	i2c_buffer[1] = {	MS6000_ISP_CMD_ERASE};
	UINT8 	ucTemp;
// Send Erase code
	for(i=0; i<1; i++){
		bRet = mfs_i2c_write_single_byte(i2c_buffer[i]);
		if( !bRet )
			goto MS6000_I2C_ERASE_FLASH_FINISH;
		udelay(15);
   	}
// Read Result
	mdelay(45);
	bRet = mfs_i2c_read_single_byte(&ucTemp);
	if( bRet && ucTemp == MS6000_ISP_ACK_ERASE_DONE ){
		nRet = MS6000_RET_SUCCESS;
	}

MS6000_I2C_ERASE_FLASH_FINISH:	
	return nRet;
}

(5)预编程和编程函数,以及download映象主函数

static int ms6000_i2c_prepare_program(void)
{
	int nRet = MS6000_RET_PREPARE_PROGRAM_FAILED,i;
	BOOL bRet;
	UINT8 i2c_buffer[4] = { MS6000_ISP_CMD_PROGRAM_TIMING,
		                    MS6000_ISP_PROGRAM_TIMING_VALUE_0,
		                    MS6000_ISP_PROGRAM_TIMING_VALUE_1,
		                    MS6000_ISP_PROGRAM_TIMING_VALUE_2};
//   Write Program timing information
	for(i=0; i<4; i++){
		bRet = mfs_i2c_write_single_byte(i2c_buffer[i]);
		if( bRet == FALSE )
			goto MS6000_I2C_PREPARE_PROGRAM_FINISH;
		udelay(15);
	}
	udelay(500);
//   Read command's result
	bRet = mfs_i2c_read_single_byte(&i2c_buffer[4]);
	if( bRet == FALSE || i2c_buffer[4] != MS6000_I2C_ACK_PREPARE_PROGRAM)
		goto MS6000_I2C_PREPARE_PROGRAM_FINISH;
	mdelay(100);
	nRet = MS6000_RET_SUCCESS;

MS6000_I2C_PREPARE_PROGRAM_FINISH:	
	return nRet;
}
static int ms6000_i2c_program_flash( UINT8 *pData, UINT16 nAddr_start, UINT8 cLength )	//FLASH one packet编程主函数
{									//参数是待编程数据,写入地址,待编程数据长度
	int nRet = MS6000_RET_PROGRAM_FLASH_FAILED;
	int     i,j;
	BOOL   bRet;
	UINT8    cData;
	UINT8    tmp;
	UINT8    cmd[4];
// Send program code	
	cmd[0] = MS6000_ISP_CMD_PROGRAM_FLASH;
	cmd[1] = (UINT8)((nAddr_start >> 8 ) & 0xFF);
	cmd[2] = (UINT8)((nAddr_start      ) & 0xFF);
	cmd[3] = cLength;
	for(i=0; i<4; i++){
		bRet = mfs_i2c_write_single_byte(cmd[i]);
		udelay(15);
		if( bRet == FALSE )
			goto MS6000_I2C_PROGRAM_FLASH_FINISH;
	}
// Check command result
	bRet = mfs_i2c_read_single_byte(&cData);
	if( bRet == FALSE || cData != MS6000_MDS_ACK_PROGRAM_FLASH ){
		goto MS6000_I2C_PROGRAM_FLASH_FINISH;
	}
// Program Data
	udelay(150);
	for(i=0; i<(int)cmd[3]; i+=2){				//一次写入两个字节,先写高位,再写低位
		bRet = mfs_i2c_write_single_byte(pData[i+1]);
		if( bRet == FALSE )
			goto MS6000_I2C_PROGRAM_FLASH_FINISH;
		udelay(100);              // Delay about 150us
		bRet = mfs_i2c_write_single_byte(pData[i]);
		udelay(150);                   // Delay about 150us
		if( bRet == FALSE )
			goto MS6000_I2C_PROGRAM_FLASH_FINISH;
	}
	nRet = MS6000_RET_SUCCESS;

MS6000_I2C_PROGRAM_FLASH_FINISH:	
	return nRet;
}
static int ms6000_download(const UINT8 *pData, const UINT16 nLength )	//download主函数,参数是映象内存首地址及映象长度
{
	int i,nRet;
	unsigned char cLength,buffer[MS6000_TRANSFER_LENGTH];
	uint16_t nStart_address=0;
	unsigned char *pOriginal_data;
//enter in download mode
	nRet = ms6000_enter_download_mode();
	if(nRet != MS6000_RET_SUCCESS)
		goto MS6000_DOWNLOAD_FINISH;

	mdelay(1);
// Erase Flash
	nRet = ms6000_i2c_prepare_erase_flash();
	if(nRet !=MS6000_RET_SUCCESS){
		goto MS6000_DOWNLOAD_FINISH;	
	}
	mdelay(1);
	nRet = ms6000_i2c_erase_flash();
	if(nRet !=MS6000_RET_SUCCESS)
		goto MS6000_DOWNLOAD_FINISH;
	mdelay(1);
// Verify erase
	nRet = mfs_i2c_read_flash( buffer, 0x00, 16 );		// Must be '0xFF' after erase
	if( nRet != MS6000_RET_SUCCESS )
		goto MS6000_DOWNLOAD_FINISH;
	for(i=0; i<16; i++){
		if( buffer[i] != 0xFF ){
			nRet = MS6000_RET_ERASE_VERIFY_FAILED;
			goto MS6000_DOWNLOAD_FINISH;
		}
	}
	mdelay(1);
// Prepare for Program flash.	
	nRet = ms6000_i2c_prepare_program();
	if( nRet != MS6000_RET_SUCCESS )
		goto MS6000_DOWNLOAD_FINISH;
	mdelay(1);
// Program flash
#if 1
	pOriginal_data  = (UINT8 *)pData;					//保留原始首地址
	nStart_address = 0;						//烧录起始地址
	cLength  = MS6000_TRANSFER_LENGTH;					//一次烧录长度,64B
	for( nStart_address = 0; nStart_address < nLength; nStart_address+=cLength ){
		if( ( nLength - nStart_address ) < MS6000_TRANSFER_LENGTH ){
			cLength  = (UINT8)(nLength - nStart_address);
			cLength += (cLength%2);		// For odd length.最后不足64B的,补上1字节当偶数处理,因为以WORD烧录
		}
		nRet = ms6000_i2c_program_flash( pOriginal_data, nStart_address, cLength );
		if( nRet != MS6000_RET_SUCCESS ){
			goto MS6000_DOWNLOAD_FINISH;
		}
		pOriginal_data  += cLength;
		udelay(500);
		printk("#");
	}
	printk("mfs6000 program finished \r\n");
#endif	
// Verify flash
#if 1
	pOriginal_data  = (UINT8 *) pData;					//保留原始首地址
	nStart_address = 0;
	cLength  = MS6000_TRANSFER_LENGTH;
	for( nStart_address = 0; nStart_address < nLength; nStart_address+=cLength ){
		if( ( nLength - nStart_address ) < MS6000_TRANSFER_LENGTH ){
			cLength = (UINT8)(nLength - nStart_address);
			cLength += (cLength%2);				// For odd length.
		}
		// Read flash
		nRet = mfs_i2c_read_flash( buffer, nStart_address, cLength );
		// Comparing
		for(i=0; i<(int)cLength; i++){
			if( buffer[i] != pOriginal_data[i] ){		//如果读出的对应地址字节与原始对应地址数据不同
				nRet = MS6000_RET_PROGRAM_VERIFY_FAILED;
				goto MS6000_DOWNLOAD_FINISH;
			}
		}
		pOriginal_data += cLength;
		udelay(500);
		printk("*");
	}
	printk("mfs6000 Verify finished \r\n");
#endif	
	nRet = MS6000_RET_SUCCESS;

MS6000_DOWNLOAD_FINISH:
	ms6000_reset_command();
	return nRet;
}

(6)升级主函数,以及TP probe函数中的处理

static int ms6000_firmware_upgrade()
{
	unsigned char NewFwVersion,OldFwVersion;
	uint16_t nBinary_length = 0;
	int nRead = 0;
	unsigned char *ptrBuff = NULL;
	int ret = MS6000_RET_FILE_ACCESS_FAILED;

	if(mfs_i2c_read_single_reg(0x21,&OldFwVersion) == true){		//在此之前,TP的供电及初始化一定要有,否则读不出来
		NewFwVersion = ms6000_GetLibVer();
		printk("mfs6000 OldFwVersion is %d,and  NewFwVersion is %d \r\n",OldFwVersion,NewFwVersion);
	}
i2c_client->addr = MS6000_8BIT_DOWNLOAD_ADDR;					//变换成TP的升级I2C地址
	if(NewFwVersion != OldFwVersion){					//如果版本号不同就升级
		ptrBuff = MS6000CTPM_FW;
		nBinary_length = sizeof(MS6000CTPM_FW);
		
//download process
		printk("start download \r\n");
		mtk_wdt_disable();
		ret = ms6000_download(ptrBuff,nBinary_length);
		mtk_wdt_get_en_setting();					//升级前后必须有禁止WDT和使能WDT的动作,否则易重启
//check process
	}
	else{								//如果版本号相同则不动作
		printk("because of the same lib, update abort!\r\n");
	}

	return ret;
}
//如下是TPD_RROBE中的改动
{
	mt65xx_eint_mask(CUST_EINT_TOUCH_PANEL_NUM);					//mask TP中断
	int UpResult;
	UpResult = ms6000_firmware_upgrade();
	if(UpResult== MS6000_RET_SUCCESS)
		printk("MFS6000 DOWNLOAD SUCCESS \r\n");
	else
		mfs6000_print_fail_result(UpResult);
	i2c_client->addr = MS6000_8BIT_I2CADDR;					//恢复TP的正常操作时I2C地址
	mt_set_gpio_mode(GPIO_I2C0_SCA_PIN, GPIO_I2C0_SCA_PIN_M_SCL);
	mt_set_gpio_mode(GPIO_I2C0_SDA_PIN, GPIO_I2C0_SDA_PIN_M_SDA);			//恢复I2C功能脚
	mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);				//unmask TP中断
}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值