解决一个I2C读写问题
之前寫關(guān)于I2C相關(guān)的文章
排查一個(gè)觸摸屏驅(qū)動(dòng)問題
MTK 平臺(tái)TP調(diào)試遇坑
1、問題
今天遇到一個(gè)問題,我們有一個(gè)芯片,I2C讀寫失敗,導(dǎo)致錄音有問題,而且是偶現(xiàn)的。
log提示看到是返回 -6
<3>[??730.336308]??(3)[2085:tinycap]es7243_read?error2,?ret?=?-6.下面流程找一下這個(gè) -6 是從哪里來的
2、I2c 發(fā)送流程
i2c-core.c
調(diào)用發(fā)送函數(shù)
/***?__i2c_transfer?-?unlocked?flavor?of?i2c_transfer*?@adap:?Handle?to?I2C?bus*?@msgs:?One?or?more?messages?to?execute?before?STOP?is?issued?to*?terminate?the?operation;?each?message?begins?with?a?START.*?@num:?Number?of?messages?to?be?executed.**?Returns?negative?errno,?else?the?number?of?messages?executed.**?Adapter?lock?must?be?held?when?calling?this?function.?No?debug?logging*?takes?place.?adap->algo->master_xfer?existence?isn't?checked.*/ int?__i2c_transfer(struct?i2c_adapter?*adap,?struct?i2c_msg?*msgs,?int?num) {unsigned?long?orig_jiffies;int?ret,?try;if?(adap->quirks?&&?i2c_check_for_quirks(adap,?msgs,?num))return?-EOPNOTSUPP;/*?i2c_trace_msg?gets?enabled?when?tracepoint?i2c_transfer?gets*?enabled.??This?is?an?efficient?way?of?keeping?the?for-loop?from*?being?executed?when?not?needed.*/if?(static_key_false(&i2c_trace_msg))?{int?i;for?(i?=?0;?i?<?num;?i++)if?(msgs[i].flags?&?I2C_M_RD)trace_i2c_read(adap,?&msgs[i],?i);elsetrace_i2c_write(adap,?&msgs[i],?i);}/*?Retry?automatically?on?arbitration?loss?*/orig_jiffies?=?jiffies;for?(ret?=?0,?try?=?0;?try?<=?adap->retries;?try++)?{ret?=?adap->algo->master_xfer(adap,?msgs,?num);if?(ret?!=?-EAGAIN)break;if?(time_after(jiffies,?orig_jiffies?+?adap->timeout))break;}if?(static_key_false(&i2c_trace_msg))?{int?i;for?(i?=?0;?i?<?ret;?i++)if?(msgs[i].flags?&?I2C_M_RD)trace_i2c_reply(adap,?&msgs[i],?i);trace_i2c_result(adap,?i,?ret);}return?ret; } EXPORT_SYMBOL(__i2c_transfer);里面有一句
ret?=?adap->algo->master_xfer(adap,?msgs,?num);這里需要找到初始化的位置,這種指針初始化的位置,一般都是和平臺(tái)設(shè)備相關(guān)的,這里也是一個(gè)技巧,初學(xué)者看到這類指針一般都會(huì)比較懵。
所以,就開始去找吧。
因?yàn)槲矣玫氖荕TK平臺(tái),所以需要去找到MTK平臺(tái)相關(guān)里面初始化的這個(gè)指針
i2c-mt65xx.c?(D:\source\kernel-4.4\drivers\i2c\busses)?line?755?:??.master_xfer?=?mtk_i2c_transfer,在文件
i2c-mt65xx.c
這里初始化了
static?const?struct?i2c_algorithm?mtk_i2c_algorithm?=?{.master_xfer?=?mtk_i2c_transfer,.functionality?=?mtk_i2c_functionality, };然后再調(diào)用發(fā)送函數(shù)
static?int?mtk_i2c_transfer(struct?i2c_adapter?*adap,struct?i2c_msg?msgs[],?int?num) {int?ret;int?left_num?=?num;struct?mtk_i2c?*i2c?=?i2c_get_adapdata(adap);ret?=?mtk_i2c_clock_enable(i2c);if?(ret)return?ret;i2c->auto_restart?=?i2c->dev_comp->auto_restart;/*?checking?if?we?can?skip?restart?and?optimize?using?WRRD?mode?*/if?(i2c->auto_restart?&&?num?==?2)?{if?(!(msgs[0].flags?&?I2C_M_RD)?&&?(msgs[1].flags?&?I2C_M_RD)?&&msgs[0].addr?==?msgs[1].addr)?{i2c->auto_restart?=?0;}}if?(i2c->auto_restart?&&?num?>=?2?&&?i2c->speed_hz?>?MAX_FS_MODE_SPEED)/*?ignore?the?first?restart?irq?after?the?master?code,*?otherwise?the?first?transfer?will?be?discarded.*/i2c->ignore_restart_irq?=?true;elsei2c->ignore_restart_irq?=?false;while?(left_num--)?{if?(!msgs->buf)?{dev_dbg(i2c->dev,?"data?buffer?is?NULL.\n");ret?=?-EINVAL;goto?err_exit;}if?(msgs->flags?&?I2C_M_RD)i2c->op?=?I2C_MASTER_RD;elsei2c->op?=?I2C_MASTER_WR;if?(!i2c->auto_restart)?{if?(num?>?1)?{/*?combined?two?messages?into?one?transaction?*/i2c->op?=?I2C_MASTER_WRRD;left_num--;}}/*?len?<=?8:?use?fifo?mode,?len?>?8:?use?DMA?mode.?*/ret?=?mtk_i2c_do_transfer(i2c,?msgs,?num,?left_num);if?(ret?<?0)goto?err_exit;msgs++;}/*?the?return?value?is?number?of?executed?messages?*/ret?=?num;err_exit:mtk_i2c_clock_disable(i2c);return?ret; }3、返回 值的代碼位置
在文件
i2c-mt65xx.c
中的函數(shù)
static?int?mtk_i2c_do_transfer(struct?mtk_i2c?*i2c,?struct?i2c_msg?*msgs,int?num,?int?left_num) {bool?dma_en;u8?*data_buf;u16?data_len;u16?read_len;u16?addr_reg;u16?start_reg;u16?control_reg;u16?restart_flag?=?0;u32?reg_4g_mode;dma_addr_t?rpaddr?=?0;dma_addr_t?wpaddr?=?0;int?ret;i2c->irq_stat?=?0;if?(i2c->auto_restart)restart_flag?=?I2C_RS_TRANSFER;reinit_completion(&i2c->msg_complete);control_reg?=?readw(i2c->base?+?OFFSET_CONTROL)?&~(I2C_CONTROL_DIR_CHANGE?|?I2C_CONTROL_RS);if?((i2c->speed_hz?>?400000)?||?(left_num?>=?1))control_reg?|=?I2C_CONTROL_RS;if?(i2c->op?==?I2C_MASTER_WRRD)control_reg?|=?I2C_CONTROL_DIR_CHANGE?|?I2C_CONTROL_RS;writew(control_reg,?i2c->base?+?OFFSET_CONTROL);/*?set?start?condition?*/if?(i2c->speed_hz?<=?100000)writew(I2C_ST_START_CON,?i2c->base?+?OFFSET_EXT_CONF);elsewritew(I2C_FS_START_CON,?i2c->base?+?OFFSET_EXT_CONF);addr_reg?=?msgs->addr?<<?1;if?(i2c->op?==?I2C_MASTER_RD)addr_reg?|=?0x1;writew(addr_reg,?i2c->base?+?OFFSET_SLAVE_ADDR);/*?Clear?interrupt?status?*/writew(restart_flag?|?I2C_HS_NACKERR?|?I2C_ACKERR?|I2C_TRANSAC_COMP,?i2c->base?+?OFFSET_INTR_STAT);writew(I2C_FIFO_ADDR_CLR,?i2c->base?+?OFFSET_FIFO_ADDR_CLR);/*?Enable?interrupt?*/writew(restart_flag?|?I2C_HS_NACKERR?|?I2C_ACKERR?|I2C_TRANSAC_COMP,?i2c->base?+?OFFSET_INTR_MASK);/*?Set?transfer?and?transaction?len?*/if?(i2c->op?==?I2C_MASTER_WRRD)?{if?(i2c->dev_comp->aux_len_reg)?{writew(msgs->len,?i2c->base?+?OFFSET_TRANSFER_LEN);writew((msgs?+?1)->len,?i2c->base?+OFFSET_TRANSFER_LEN_AUX);}?else?{writew(msgs->len?|?((msgs?+?1)->len)?<<?8,i2c->base?+?OFFSET_TRANSFER_LEN);}writew(I2C_WRRD_TRANAC_VALUE,?i2c->base?+?OFFSET_TRANSAC_LEN);}?else?{writew(msgs->len,?i2c->base?+?OFFSET_TRANSFER_LEN);writew(num,?i2c->base?+?OFFSET_TRANSAC_LEN);}/*?Prepare?buffer?data?to?start?transfer?*/if?(msgs->len?>?I2C_FIFO_SIZE?||?(i2c->op?==?I2C_MASTER_WRRD?&&(msgs?+?1)->len?>?I2C_FIFO_SIZE))?{dma_en?=?true;if?(i2c->op?==?I2C_MASTER_RD)?{writel(I2C_DMA_INT_FLAG_NONE,?i2c->pdmabase?+?OFFSET_INT_FLAG);writel(I2C_DMA_CON_RX,?i2c->pdmabase?+?OFFSET_CON);rpaddr?=?dma_map_single(i2c->dev,?msgs->buf,msgs->len,?DMA_FROM_DEVICE);if?(dma_mapping_error(i2c->dev,?rpaddr))return?-ENOMEM;if?(i2c->dev_comp->support_33bits)?{reg_4g_mode?=?mtk_i2c_set_4g_mode(rpaddr);writel(reg_4g_mode,?i2c->pdmabase?+?OFFSET_RX_4G_MODE);}writel((u32)rpaddr,?i2c->pdmabase?+?OFFSET_RX_MEM_ADDR);writel(msgs->len,?i2c->pdmabase?+?OFFSET_RX_LEN);}?else?if?(i2c->op?==?I2C_MASTER_WR)?{writel(I2C_DMA_INT_FLAG_NONE,?i2c->pdmabase?+?OFFSET_INT_FLAG);writel(I2C_DMA_CON_TX,?i2c->pdmabase?+?OFFSET_CON);wpaddr?=?dma_map_single(i2c->dev,?msgs->buf,msgs->len,?DMA_TO_DEVICE);if?(dma_mapping_error(i2c->dev,?wpaddr))return?-ENOMEM;if?(i2c->dev_comp->support_33bits)?{reg_4g_mode?=?mtk_i2c_set_4g_mode(wpaddr);writel(reg_4g_mode,?i2c->pdmabase?+?OFFSET_TX_4G_MODE);}writel((u32)wpaddr,?i2c->pdmabase?+?OFFSET_TX_MEM_ADDR);writel(msgs->len,?i2c->pdmabase?+?OFFSET_TX_LEN);}?else?{writel(I2C_DMA_CLR_FLAG,?i2c->pdmabase?+?OFFSET_INT_FLAG);writel(I2C_DMA_CLR_FLAG,?i2c->pdmabase?+?OFFSET_CON);wpaddr?=?dma_map_single(i2c->dev,?msgs->buf,msgs->len,?DMA_TO_DEVICE);if?(dma_mapping_error(i2c->dev,?wpaddr))return?-ENOMEM;rpaddr?=?dma_map_single(i2c->dev,?(msgs?+?1)->buf,(msgs?+?1)->len,?DMA_FROM_DEVICE);if?(dma_mapping_error(i2c->dev,?rpaddr))?{dma_unmap_single(i2c->dev,?wpaddr,msgs->len,?DMA_TO_DEVICE);return?-ENOMEM;}if?(i2c->dev_comp->support_33bits)?{reg_4g_mode?=?mtk_i2c_set_4g_mode(wpaddr);writel(reg_4g_mode,?i2c->pdmabase?+?OFFSET_TX_4G_MODE);reg_4g_mode?=?mtk_i2c_set_4g_mode(rpaddr);writel(reg_4g_mode,?i2c->pdmabase?+?OFFSET_RX_4G_MODE);}writel((u32)wpaddr,?i2c->pdmabase?+?OFFSET_TX_MEM_ADDR);writel((u32)rpaddr,?i2c->pdmabase?+?OFFSET_RX_MEM_ADDR);writel(msgs->len,?i2c->pdmabase?+?OFFSET_TX_LEN);writel((msgs?+?1)->len,?i2c->pdmabase?+?OFFSET_RX_LEN);}if?(i2c->op?!=?I2C_MASTER_RD)writel(I2C_DMA_START_EN,?i2c->pdmabase?+?OFFSET_EN);}?else?{dma_en?=?false;if?(i2c->op?!=?I2C_MASTER_RD)?{data_buf?=?msgs->buf;data_len?=?msgs->len;while?(data_len--)writew_relaxed(*(data_buf++),?i2c->base?+?OFFSET_DATA_PORT);}}if?(!i2c->auto_restart)?{start_reg?=?I2C_TRANSAC_START;}?else?{start_reg?=?I2C_TRANSAC_START?|?I2C_RS_MUL_TRIG;if?(left_num?>=?1)start_reg?|=?I2C_RS_MUL_CNFG;}writew(start_reg,?i2c->base?+?OFFSET_START);if?(dma_en?&&?i2c->op?==?I2C_MASTER_RD)writel(I2C_DMA_START_EN,?i2c->pdmabase?+?OFFSET_EN);ret?=?wait_for_completion_timeout(&i2c->msg_complete,i2c->adap.timeout);/*?Clear?interrupt?mask?*/writew(~(restart_flag?|?I2C_HS_NACKERR?|?I2C_ACKERR?|I2C_TRANSAC_COMP),?i2c->base?+?OFFSET_INTR_MASK);if?(dma_en)?{if?(i2c->op?==?I2C_MASTER_WR)?{dma_unmap_single(i2c->dev,?wpaddr,msgs->len,?DMA_TO_DEVICE);}?else?if?(i2c->op?==?I2C_MASTER_RD)?{dma_unmap_single(i2c->dev,?rpaddr,msgs->len,?DMA_FROM_DEVICE);}?else?{dma_unmap_single(i2c->dev,?wpaddr,?msgs->len,DMA_TO_DEVICE);dma_unmap_single(i2c->dev,?rpaddr,?(msgs?+?1)->len,DMA_FROM_DEVICE);}}if?(ret?==?0)?{dev_dbg(i2c->dev,?"addr:?%x,?transfer?timeout\n",?msgs->addr);mtk_i2c_init_hw(i2c);return?-ETIMEDOUT;}completion_done(&i2c->msg_complete);if?(i2c->irq_stat?&?(I2C_HS_NACKERR?|?I2C_ACKERR))?{dev_dbg(i2c->dev,?"addr:?%x,?transfer?ACK?error\n",?msgs->addr);mtk_i2c_init_hw(i2c);return?-ENXIO;}if?(!dma_en?&&?i2c->op?!=?I2C_MASTER_WR)?{data_buf?=?(i2c->op?==?I2C_MASTER_RD)???msgs->buf?:(msgs?+?1)->buf;data_len?=?(i2c->op?==?I2C_MASTER_RD)???msgs->len?:(msgs?+?1)->len;read_len?=?(readw(i2c->base?+?OFFSET_FIFO_STAT)?>>?4)?&?0xf;if?(read_len?==?data_len)?{while?(data_len--)*(data_buf++)?=?readw_relaxed(i2c->base?+?OFFSET_DATA_PORT);}?else?{dev_dbg(i2c->dev,?"data_len?%x,?read_len?%x,?fifo?read?len?error\n",data_len,?read_len);mtk_i2c_init_hw(i2c);return?-EIO;}}return?0; }下面這段代碼
?if?(i2c->irq_stat?&?(I2C_HS_NACKERR?|?I2C_ACKERR))?{dev_dbg(i2c->dev,?"addr:?%x,?transfer?ACK?error\n",?msgs->addr);mtk_i2c_init_hw(i2c);return?-ENXIO;}宏定義
errno-base.h
#define?ENXIO???6?/*?No?such?device?or?address?*/表示就是找不到設(shè)備,沒有應(yīng)答
我用邏輯分析儀抓波形,確實(shí)存在沒有應(yīng)答的情況下打印了上面的錯(cuò)誤日志。
解決
問題日志
<6>[?1594.422871]??(3)[1663:AudioInMic][ES7243]:?es7243_pcm_startup()?line:?444?start. <6>[?1594.432778]??(3)[1663:AudioInMic][ES7243]:?es7243_pcm_startup()?line:?444?start. <6>[?1594.432902]??(3)[1663:AudioInMic][ES7243]:?es7243_pcm_hw_params()?line:?472?es7243_pcm_hw_params <6>[?1594.432918]??(3)[1663:AudioInMic][ES7243]:?es7243_set_bias_level()?line:?568?level:1 <6>[?1594.433367]??(3)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x00?val:0x09?ok <6>[?1594.433741]??(0)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x06?val:0x18?ok <6>[?1594.434121]??(2)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x07?val:0x80?ok <6>[?1594.434506]??(0)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x01?val:0x0c?ok <6>[?1594.434886]??(0)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x02?val:0x10?ok <6>[?1594.435288]??(2)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x03?val:0x04?ok <6>[?1594.435682]??(3)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x04?val:0x02?ok <6>[?1594.436136]??(1)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x05?val:0x1a?ok <6>[?1594.436574]??(3)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x09?val:0x3f?ok <6>[?1594.437004]??(0)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x06?val:0x00?ok <6>[?1594.437424]??(3)[1663:AudioInMic][ES7243]:?es7243_write()?line:?161?es7243_write?reg:0x05?val:0x36?ok <3>[?1594.437676]??(3)[1663:AudioInMic]es7243_write?13?error->[REG-0x08,val-0x07] <3>[?1594.437907]??(3)[1663:AudioInMic]es7243_read?error1 <3>[?1594.438220]??(3)[1663:AudioInMic]es7243_write?13?error->[REG-0x01,val-0x8c] <6>[?1594.438246]??(3)[1663:AudioInMic][ES7243]:?es7243_update_bits()?line:?175?value:12 <3>[?1594.438951]??(3)[1663:AudioInMic]es7243_read?error2,?ret?=?-6. <6>[?1594.438990]??(3)[1663:AudioInMic][ES7243]:?es7243_pcm_hw_params()?line:?538?es7243_pcm_hw_params538?--?Reg?08?---->?0x0! <3>[?1594.439477]??(3)[1663:AudioInMic]es7243_read?error2,?ret?=?-6. <6>[?1594.439510]??(3)[1663:AudioInMic][ES7243]:?es7243_pcm_hw_params()?line:?540?es7243_pcm_hw_params540?--?Reg?05?---->?0x0!復(fù)現(xiàn)了十幾把,發(fā)現(xiàn)每次都是剛開始I2C可以讀寫,后面再讀寫的時(shí)候,就容易出現(xiàn)I2C操作失敗的情況。
FAE給的答復(fù)是
I2C走線是否有其他干擾
I2C有沒有加RC濾波電路
硬件已經(jīng)確定了,想再修改硬件可能性比較小,也比較麻煩,硬件測(cè)量了I2C波形,也沒有發(fā)現(xiàn)異常。故此,還是想在軟件上做規(guī)避。
我猜測(cè)可能是芯片操作過快,芯片沒有來得及反應(yīng),而且每次操作開始I2C都是可以讀寫的,所以就想在讀寫函數(shù)中阻塞一會(huì)會(huì)來規(guī)避這個(gè)問題。
patch
diff?--git?a/kernel-4.4/sound/soc/codecs/es7243.c?b/kernel-4.4/sound/soc/codecs/es7243.c index?272f5dbf88..0e6a1e6bcc?100755 ---?a/kernel-4.4/sound/soc/codecs/es7243.c +++?b/kernel-4.4/sound/soc/codecs/es7243.c @@?-32,6?+32,7?@@#include?<sound/tlv.h>#include?<sound/initval.h>#include?<linux/regmap.h> +#include?<linux/delay.h>#ifdef?CONFIG_OF#include?<linux/of.h>#include?<linux/of_irq.h> @@?-127,6?+128,7?@@?static?int?es7243_read(u8?reg,?u8?*rt_value,?struct?i2c_client?*client)read_cmd[0]?=?reg;cmd_len?=?1;+???????udelay(2000);if?(client->adapter?==?NULL)pr_err("es7243_read?client->adapter==NULL\n");@@?-141,6?+143,7?@@?static?int?es7243_read(u8?reg,?u8?*rt_value,?struct?i2c_client?*client)pr_err("es7243_read?error2,?ret?=?%d.\n",?ret);return?-1;} +ES7243_DEBUG("es7243_read?OK\n");return?0;} @@?-153,12?+156,14?@@?static?int?es7243_write(u8?reg,?unsigned?char?value,?struct?i2c_client?*client)write_cmd[0]?=?reg;write_cmd[1]?=?value;+???????udelay(2000);ret?=?i2c_master_send(client,?write_cmd,?2);if?(ret?!=?2)?{pr_err("es7243_write?%x?error->[REG-0x%02x,val-0x%02x]\n",client->addr,reg,value);return?-1;}ES7243_DEBUG("es7243_write?reg:0x%.2x?val:0x%.2x?ok?\n",reg,value); +return?0;}修改后,驗(yàn)證了十幾把,確實(shí)沒有再發(fā)現(xiàn)問題,如果再有問題的話,再分析。
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
我的知識(shí)小密圈
關(guān)注公眾號(hào),后臺(tái)回復(fù)「1024」獲取學(xué)習(xí)資料網(wǎng)盤鏈接。
歡迎轉(zhuǎn)發(fā),在看,評(píng)論~
總結(jié)
以上是生活随笔為你收集整理的解决一个I2C读写问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: IIC踩过的坑
 - 下一篇: mac mysql常用命令