Linux I2C驅動完全分析(一)


 博主按:其實老早就想寫這個I2C的了,期間有各種各樣的事情給耽誤了。借着五一放假的時間把這個寫出來,供同志們參考。以后會花一些時間深入研究下內核,雖然以前對內核也有所了解,但是還不系統。I2C的硬件結構並不復雜,一個適配器加幾個設備而已。Linux下驅動的體系結構看着挺復雜,實際也是比較簡單的。在本文中我還是使用實際的例子,結合硬件和軟件兩個方面來介紹。希望能給初學的同志們一些幫助,另外拋磚引玉,希望高手能給一些指點。話不多說,開整!~

 

本文用到的一些資源:

   1. Source Insight軟件

   2. mini2440原理圖。 下載地址http://wenku.baidu.com/view/0521ab8da0116c175f0e48fe.html

   3. S3C2440 datasheet

   4. AT24C08 datasheet

   5. Bq27200 datasheet

   6. kernel 2.6.31中的At24.c ,Bq27x00_battery.c和i2c-s3c2410.c

   7. mini2440的板文件mach-mini2440.c

   8. 參考資料:《linux設備驅動開發詳解(第2版)》 by 宋寶華

 

本文的結構:

第一部分:At24C08驅動

   1. mini2440中at24c08的電氣連接

   2. Linux中I2C驅動框架分析

   3. I2C總線驅動代碼分析

   4. at24c08驅動代碼分析

第二部分:Bq27200驅動

   1. Bq27200的典型應用電路

   2. 主要分析一下ba27x00的代碼,對比at24c08來加深理解。

 

---------------------我是分割線----------------------

 

第一部分

1. mini2440中at24c08的電氣連接及其板文件

       如下圖。

                                

24C08的I2C接口是與2440的IICSCL/IICSDA直接相連的。在2440內部集成了一個I2C控制器,可以通過寄存器來控制它。先來和這四個寄存器混個臉熟吧,后面分析時還會經常用到這四個寄存器。

   

 在mini2440的板文件中可以找到關於at24c08的內容,如下:

可以看出,在mini2440的init函數中注冊了一個i2c的設備,這個設備我們使用了一個結構體i2c_board_info來描述。這個結構體定義在i2c.h文件中。如下:

其中的platform_data又指向一個at24_platform_data結構體。

 

以上只是at24c08的部分,在板文件中還可以看到關於2440內部i2c控制器的部分,如下:

其中s2c_device_i2c0定義在arch/arm/plat-s3c/Dev-i2c0.c中(在同一目錄下還可以看到很多Dev-開頭的c文件,都是2440內部集成的各種設備),仔細看下面的代碼再對比2440的datasheet就可以很清楚的知道:

   * 控制器的IO起始地址為S3C_PA_IIC =0x54000000,大小是4K,中斷號是43 = IRQ_IIC      S3C2410_IRQ(27)

   * 控制器名是"s3c2410-i2c"

   

2. Linux中I2C驅動框架分析

    這部分是本文的重點部分。根據上面的電氣連接關系我們可以看出,我們要想操作24c08,必須要做兩方面的驅動。

       第一方面: 2440中I2C控制器的驅動,有了這部分驅動,我們才可以操作控制器來產生I2C的時序信號,來發送數據和接收數據。

       第二方面: 24C08的驅動,有了這部分驅動,才能使用控制器正確操作芯片,來讀取和存放數據。

    在Linux系統中,對上邊第一方面的實現叫做I2C總線驅動,對第二方面的實現叫做I2C設備驅動。一般來說,如果CPU中集成了I2C控制器並且Linux內核支持這個CPU,那么總線驅動方面就不用我們操心了,內核已經做好了。但如果CPU中沒有I2C控制器,而是外接的話,那么就要我們自己實現總線驅動了。對於設備驅動來說,一般常用的驅動也都包含在內核中了,如果我們用了一個內核中沒有的芯片,那么就要自己來寫了。

    Linux中I2C體系結構如下圖所示(圖片來源於網絡)。圖中用分割線分成了三個層次:用戶空間(也就是應用程序),內核(也就是驅動部分)和硬件(也就是實際物理設備,這里就是2440中的i2c控制器和at24c08)。這個夠清晰了吧?我們現在就是要研究中間那一層。

   

 由上圖我們還可以看出哪些信息呢?

  1). 可以看到幾個重要的組成部分,它們是:Driver,Client,i2c-dev,i2c-core,Algorithm,Adapter。這幾個部分在內核中都有相應的數據結構,定義在i2c.h文件中,盡量避免粘貼打斷代碼來湊數,就不貼出來了。簡要概括一下每個結構體的意義。

       Driver --> struct i2c_driver 

          這個結構體對應了驅動方法,重要成員函數有probe,remove,suspend,resume。

          還包括一個重要的數據結構: struct i2c_device_id *id_table; 如果驅動可以支持好幾個設備,那么這里面就要包含這些設備的ID

 

       Client --> struct i2c_client

          應用程序是選擇性失明的,它只能看到抽象的設備文件,其他部分都是看不見的。圖中只有Client與應用程序有聯系,所以我們可以大膽得出結論:這個Client是對應於真實的物理設備,在本文就是at24c08。 所以很顯然這個結構體中的內容應該是描述設備的。包含了芯片地址,設備名稱,設備使用的中斷號,設備所依附的控制器,設備所依附的驅動等內容。

 

       Algorithm -->struct i2c_algorithm

          Algorithm就是算法的意思。在這個結構體中定義了一套控制器使用的通信方法。其中關鍵函數是master_xfer()。我們實際工作中的重要一點就是要實現這個函數。

 

       Adapter --> struct i2c_adapter

           這個結構體對應一個控制器。其中包含了控制器名稱,algorithm數據,控制器設備等。

 

 2). 可以看出,i2c-core起到了關鍵的承上啟下的作用。事實上也是這樣,我們將從這里展開來分析。源代碼位於drivers/i2c/i2c-core.c中。在這個文件中可以看到幾個重要的函數。

   *增加/刪除i2c控制器的函數

 

  

   *增加/刪除設備驅動的函數

 

    *增加/刪除i2c設備的函數

注:在2.6.30版本之前使用的是i2c_attach_client()和i2c_detach_client()函數。之后attach被merge到了i2c_new_device中,而detach直接被unresister取代。實際上這兩個函數內部都是調用了device_register()和device_unregister()。源碼如下:

    *I2C傳輸、發送和接收函數

 其中send和receive分別都調用了transfer函數,而transfer也不是直接和硬件交互,而是調用algorithm中的master_xfer()函數,所以我們要想進行數據傳輸,必須自己來實現這個master_xfer()函數,這是總線驅動開發的重點之一。下面以read()系統調用的流程來簡單梳理一下:

 

(待續)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM