2016-01-29 30 views
3

我想從需要多次啓動操作的i2c從機讀取其寄存器值。我發現它不支持多重啓動操作,我無法從這個I2C從設備(以太網供電管理器PD69104B1)讀取數據。由於我在Linux內核3.18.21中追蹤了I2C驅動程序,我發現它不支持多啓動操作。爲什麼重複啓動基於i2c操作不支持在Linux?

我仍然在尋找擴展驅動程序的方式,如果需要這個i2c slave或其他需要的東西。

我使用i2c-tools 3.2.1。 我嘗試

$ i2cdump -y 0 0x20 

但我可以看到相同的值,這意味着它首先讀取寄存器每次。

$ i2cget -y 0 0x20 0x12 

或任何其他寄存器地址返回與第一個寄存器相同的值。

這從支持兩個讀操作:

  • 字節讀 - 寫地址得到它的價值,但這個需要多開始
  • 塊讀取 - 開始閱讀和I2C從會像0×00 0×01序列給出寄存器值....(先登記,第二,第三,第四......等)

我嘗試所有可能的方式:

  • i2c_smbus_access()
  • i2c_smbus_write_byte()
  • i2c_smbus_read_block_data()
  • write()
  • read()

但隨後大部分時間I2C總線的進入超時錯誤和掛起情況。

任何人有想法如何在Linux中實現這一點?

Update0:

這I2C從設備需要獨特讀週期:

  • 方向的改變:S地址Wr的[A] RegAddress [A] S地址路[A] [RegValue] p

  • 短讀:S地址RD [A] [RegValue]芘

這裏最後的值從我回來2C從機不期望ACK。

我嘗試使用I2C_M_NO_RD_ACK,但沒有太多幫助。我讀了一些價值,然後得到FF。

此POE I2C從設備在SCL上的I2C時間爲14ms,這是有點疑問。這看起來像i2c非標準,因爲i2c可以在0HZ上工作,即只要需要,SCL可以由主人拉伸。 Linux絕對不是實時操作系統,因此無法保證實現這個時間,並且可能會發生i2c從屬SCL超時重置。這是我目前的結論!使用

I2C消息符號是: https://www.kernel.org/doc/Documentation/i2c/i2c-protocol

+0

幾件事情:SOC/HW你使用的是哪個?某些i2c主機控制器可能不支持重複啓動(這就是爲什麼他們的驅動程序可能沒有重複啓動代碼)。檢出支持'REPEAT_START'作爲Tegra I2C主機控制器的[Tegra-I2C驅動程序](http://lxr.free-electrons.com/source/drivers/i2c/busses/i2c-tegra.c#L554)支持重複啓動模式。另外像'i2cset' /'i2cget'這樣的用戶空間工具非常簡單,並且可能不支持i2c操作的重複啓動模式。 – TheCodeArtist

+1

@TheCodeArtist它看起來像OP只是使用不正確的API發送重複啓動。我在回答中添加了關於用戶空間方法的註釋。 –

+0

@ TheCodeArtist它的mediatek MT7621A SoC。已經,我也檢查,如果i2c主機控制器或其驅動程序不支持重複啓動。 – coder007

回答

5

爲什麼重複啓動基於I2C操作,在linux下不支持?

事實上,他們是支持的。

如果您正在尋找在用戶空間執行重複的啓動條件的方式,你可能需要做ioctl()I2C_RDWR要求,如它的描述here(見原題最後的代碼片段)和here(代碼有問題)。

下面描述了在內核空間中執行重複啓動的方式。


在Linux內核I2C讀取repeated start condition操作由默認爲組合(寫/讀)消息來執行。

下面是一個例子如何執行組合I2C傳輸:

/** 
* Read set of registers via I2C using "repeated start" condition. 
* 
* Two I2C messages are being sent by this function: 
* 1. I2C write operation (write register address) with no STOP bit in the end 
* 2. I2C read operation 
* 
* @client: I2C client structure 
* @reg: register address (subaddress) 
* @len: bytes count to read 
* @buf: buffer which will contain read data 
* 
* Returns 0 on success or negative value on error. 
*/ 
static int i2c_read_regs(struct i2c_client *client, u8 reg, u8 len, u8 *buf) 
{ 
    int ret; 
    struct i2c_msg msg[2] = { 
     { 
      .addr = client->addr, 
      .len = 1, 
      .buf = &reg, 
     }, 
     { 
      .addr = client->addr, 
      .flags = I2C_M_RD, 
      .len = len, 
      .buf = buf, 
     } 
    }; 

    ret = i2c_transfer(client->adapter, msg, 2); 
    if (ret < 0) { 
     dev_err(&client->dev, "I2C read failed\n"); 
     return ret; 
    } 

    return 0; 
} 

要閱讀僅1個字節(單個寄存器值),可以使用下一個輔助函數:

/** 
* Read one register via I2C using "repeated start" condition. 
* 
* @client: I2C client structure 
* @reg: register address (subaddress) 
* @val: variable to store read value 
* 
* Returns 0 on success or negative value on error. 
*/ 
static int i2c_read_reg(struct i2c_client *client, u8 reg, u8 *val) 
{ 
    return i2c_read_regs(client, reg, 1, val); 
} 

下面是例證對於i2c_read_regs(client, reg, 1, val)電話:

  • 設備地址是client->addr
  • 寄存器地址是reg
  • 1意味着我們想要讀出的數據的1個字節(上圖片粉紅色矩形)
  • 讀出的數據將駐留在val

enter image description here


注意:如果您的I2C控制器(或其驅動程序)不支持組合消息中的重複啓動,則仍然可以使用bit-bang實現I2C,它是i2c-gpio驅動程序。


如果什麼都行不通,您可以嘗試下一步作爲最後的手段。出於某種原因,我不太記得了,爲了使重複開始工作,我需要添加I2C_M_NOSTART到第一條消息的.flags,像這樣:

struct i2c_msg msg[2] = { 
    { 
     .addr = client->addr, 
     .flags = I2C_M_NOSTART, 
     .len = 1, 
     .buf = &reg, 
    }, 
    { 
     .addr = client->addr, 
     .flags = I2C_M_RD, 
     .len = len, 
     .buf = buf, 
    } 
}; 

Documentation/i2c/i2c-protocol指出:

如果您爲第一個部分消息 設置了I2C_M_NOSTART變量,我們不生成Addr,但我們確實生成了startbit S


參考文獻:

[1] I2C on STLinux

+0

我用邏輯分析器檢查過,並且知道每條消息都有自己的開始和結束,並且這樣的讀取限制爲16。你對如何生成UPDATE0中提到的上述消息格式有任何評論嗎? – coder007

+0

這是不完全清楚的說什麼。你使用邏輯分析儀哪些代碼?哪個消息有自己的開始和結束?你的意思可能是開始和停止?你正在執行從內核或用戶空間讀取?你的意思是什麼信息格式?請詳細說明。 –

相關問題