在驅動開發過程中,我們有時會碰到這種應用:比如說某款晶片的韌體不是固定的,是可以後期升級的。那麼在每次系統開機時,需要做個檢測,如果檢測到提供了新的韌體,那麼在第一次開機時就升級韌體。之後由於儲存了新的韌體版本號碼可供檢測,就不用再開機升級了。
以一款I2C的觸控螢幕晶片為例,假設供應商提供的新韌體檔案名稱是Us3x06eb_use.it,將該檔案放在觸控螢幕驅動.c的同目錄下,那麼需要做的就是在觸控螢幕的Probe函數裡面加入對應的版本號碼檢測處理,並決定是否升級。如果需要升級,將目標韌體通過I2C寫入即可。
typedef enum{ ERR_OK, ERR_MODE, ERR_READID, ERR_ERASE, ERR_STATUS, ERR_ECC, ERR_DL_ERASE_FAIL, ERR_DL_PROGRAM_FAIL, ERR_DL_VERIFY_FAIL}E_UPGRADE_ERR_TYPE;#define FTS_PACKET_LENGTH 2 //一次寫兩個位元組,作為一個PACKETstatic unsigned char CTPM_FW[] = //載入目標韌體{ #include "Us3x06eb_use.it"};static int fts_i2c_txdata(u8 *txdata, int length) //一次通過I2C傳輸多位元組資料{ int ret; struct i2c_msg msg; msg.addr = i2c_client->addr; msg.flags = 0; msg.len = length; msg.buf = txdata; ret = i2c_transfer(i2c_client->adapter, &msg, 1); if(ret < 0) { pr_err("%s i2c write error: %d\n", __func__, ret); } return ret;}static bool i2c_write_interface(u8 *pbt_buf, int dw_lenth) //通過I2C寫多個資料{ int ret; ret = i2c_master_send(i2c_client, pbt_buf, dw_lenth); if(ret <= 0) { printk("[TSP]i2c_write_interface error line = %d, ret = %d\n", __LINE__, ret); return FTS_FALSE; } return FTS_TRUE;}static bool i2c_read_interface(u8 *pbt_buf, int dw_lenth) //通過I2C讀多個資料{ int ret; ret = i2c_master_recv(i2c_client, pbt_buf, dw_lenth); if(ret <= 0) { printk("[TSP]i2c_read_interface error\n"); return FTS_FALSE; } return FTS_TRUE;}static bool fts_register_write(u8 reg_name, u8 *tx_buf) //往寄存器寫單位元組資料{ u8 write_cmd[2] = {0}; write_cmd[0] = reg_name; write_cmd[1] = *tx_buf; return i2c_write_interface(write_cmd, 2);}static bool fts_register_read(u8 reg_name, u8 *rx_buf, int rx_length) //從寄存器讀多個資料{ u8 read_cmd[2] = {0}; u8 cmd_len = 0; read_cmd[0] = reg_name; cmd_len = 1; /*send register addr*/ if(!i2c_write_interface(&read_cmd[0], cmd_len)) { return FTS_FALSE; } if(!i2c_read_interface(rx_buf, rx_length)) { return FTS_FALSE; } return FTS_TRUE;}
E_UPGRADE_ERR_TYPE fts_ctpm_fw_upgrade(u8 *pbt_buf, int dw_lenth) //編程燒錄細節不闡述,執行個體會在本部落格的續篇中列出
{
//將資料劃分成相應的PACKET,一次通過I2C寫入晶片中。有幾個問題需要注意:(1)要注意分包的銜接,資料長度未必恰好能劃分成整數個包,那麼最後一個包要單獨
//處理;(2)資料校正,比如說晶片帶自動異或校正的話,一方面我們在發送的過程中要及時進行資料校正運算,另一方面在資料發送完畢後,可以把這個校正值跟校正
//寄存器的值進行比較,從而判斷當前傳輸是否有效。
}
int fts_ctpm_fw_upgrade_with_i_file(void){ u8 *pbt_buf = 0x0; int ret; pbt_buf = CTPM_FW; ret = fts_ctpm_fw_upgrade(pbt_buf, sizeof(CTPM_FW)); //升級特定檔案 return ret;}static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) //TP的probe函數{ ............. { u8 reg_val=0; mdelay(50); fts_register_read(0xA6,_val,1); //讀出目前的版本號 if(reg_val<TP_LIB_VERSION) //如果目前的版本號小於待升級版本號碼,進行升級 { printk("TP firmware version OK, start upgrade\n"); fts_ctpm_fw_upgrade_with_i_file(); } } .............}