1. 程式人生 > >linux核心的I2C子系統

linux核心的I2C子系統

1、I2C匯流排彙總概念

  (1)三根訊號線:SCL、SDA、GND

  (2)同步、序列、電平、低速、近距離

  (3)匯流排式結構,支援多個裝置掛接在同一條總線上

  (4)主從式結構,通訊雙方必須一個為主(master)一個為從(slave),主裝置掌握每次通訊的主動權,從裝置按照主裝置的節奏被動響應(如果從裝置需要主裝置訪問,需要增加中斷功能,比如觸控式螢幕,當有位移變化,觸控式螢幕晶片會產生一箇中斷,然後主裝置就會訪問從裝置)。每個從裝置在匯流排中有唯一的地址(slave address),主裝置通過從地址找到自己要通訊的從裝置(本質是廣播)。

  (5)I2C主要用途就是主SoC與外圍裝置之間的通訊,最大的優勢就是總線上可以擴充套件多個外圍裝置的支援,比如常見的物聯網感測器晶片。

  (6)電容觸控式螢幕晶片的多個引腳構成2個介面。一個介面是I2C的,負責和主SoC連線(本身作為從裝置),主SoC通過該介面初始化及控制電容觸控式螢幕晶片、晶片通過該介面向SoC彙報觸控事件的資訊(觸控座標等),我們使用電容觸控式螢幕時重點關注的是這個介面;另一個介面是電容觸控板的管理介面,電容觸控式螢幕晶片通過該介面來控制觸控板硬體。該介面是電容觸控式螢幕公司關心的,他們的觸控式螢幕晶片內部韌體程式設計要處理這部分,我們使用電容觸控式螢幕的人並不關心這裡。

 

2、linux核心的I2C驅動框架總覽

  (1)I2C驅動框架的主要目標是:讓驅動開發者可以在核心中方便的新增自己的I2C裝置的驅動程式,從而可以更加容易的在linux下驅動自己的I2C介面硬體。

  (2)原始碼中I2C相關的驅動均位於:driver/i2c目錄下。linux系統提供兩種I2C驅動實現方法:第一種叫i2c-dev,對應於driver/i2c/i2c-dev.c,這種方法只是封裝了主機(I2C master,一般是SOC中內建的I2C控制器)的I2C的基本操作,並且嚮應用層提供相應的操作介面,應用層程式碼需要自己去實現對slave的控制和操作,所以這種I2C驅動相當於只是提供給應用層可以訪問slave硬體裝置的介面,本身並未對硬體做任何操作,應用需要實現對硬體的操作,因此寫應用的人必須對硬體非常瞭解,其實相當於傳統的驅動中乾的活兒丟給應用去做了,所以這種I2C驅動又叫做“應用層驅動”,這種方式並不主流,它的優勢是把差異化都放在應用中,這樣在裝置比較難纏(尤其是slave是非標準I2C時)時不用動驅動,而只需要修改應用就可以實現對各種裝置的驅動。

  (3)第二種I2C驅動是所有的程式碼都放在驅動層實現,直接嚮應用層提供最終結果。應用層甚至不需要知道這裡面有I2C存在,譬如電容式觸控式螢幕,直接嚮應用層提供dev/input/event1的操作介面,應用層程式設計的人根本不知道event1中涉及到了I2C。

 

3、I2C子系統的4個關鍵結構體

  (1)struct i2c_adapter,I2C介面卡(即I2C主機控制器驅動),主要是用於操控S5PV210內部的I2C外設,S5PV210內部的I2C外設包含5個暫存器(I2CCON0、I2CSTAT0、I2CADD0、I2CDS0、I2CLC0),該檔案就是用來操控這5個暫存器,與I2C從裝置沒有任何關係。

  (2)struct i2c_algorithm,I2C演算法,主要是用來描述I2C主控裝置與從機之間進行通訊的演算法(即時序),I2C主控與外設通訊是通過I2C介面卡(主控制器)的,所以該結構體一般是包含在i2c_adapter裡面

  (3)struct i2c_client,I2C(從機)裝置資訊,硬體的資訊放在i2c_client檔案裡面,i2c_client和i2c_driver在I2C匯流排裡面進行匹配,匹配上之後i2c_client將硬體資訊傳給i2c_driver,i2c_driver在probe函式裡面使用這些硬體資訊對硬體進行初始化和操作,從而使硬體可以工作。

  (4)struct i2c_driver, I2C(從機)裝置驅動

 

4、關鍵檔案分析

  (1)i2c-core.c 驅動開發中核心給我們實現的那一部分,裡面的程式碼全部和硬體無關,主要是I2C軟體層面的一些程式碼。

  (2)busses目錄 裡面放置的是一些已經移植好的i2c_adapter(主控制器驅動),我們主要分析的是i2c_s3c2410.c(這裡面放置的就是S3C2410的i2c主控制器的操作(S5PV210內建的I2C主控制器與S3C2410的一樣(5個暫存器一樣))),

  (3)algos目錄 linux核心自己實現的一些演算法。

 

5、I2C子系統程式碼之i2c-core.c詳細分析

  (1)該檔案也是當作一個模組來實現的,因此需要找到insmod和rmmod所執行的函式。
      postcore_initcall(i2c_init); //說明該函式不是動態載入的,而是開機的時候載入的模組。i2c_init主要是用來裝載I2C匯流排(整個I2C是怎樣初始化起來的)
       retval = bus_register(&i2c_bus_type); //註冊了一個I2C匯流排模組

    module_exit(i2c_exit); 

  (2)i2c匯流排的匹配機制

    a、match函式
    b、probe函式

    
    總結:I2C總線上有2條分支:i2c_client鏈和i2c_driver鏈,當任何一個driver或者client去註冊時,I2C匯流排都會呼叫match函式去對client.name和driver.id_table.name進行迴圈匹配。如果driver.id_table中所有的id都匹配不上則說明client並沒有找到一個對應的driver,沒了;如果匹配上了則標明client和driver是適用的,那麼I2C匯流排會呼叫自身的probe函式,自身的probe函式又會呼叫driver中提供的probe函式,driver中的probe函式會對裝置進行硬體初始化和後續工作。

  (3)核心層開放給其他部分的註冊介面
    a、i2c_add_adapter/i2c_add_numbered_adapter   註冊adapter(主機控制器端的註冊)的,比如在i2c-s3c2410.c裡面呼叫 i2c_add_numbered_adapter(&i2c->adap)註冊一個adapter;

    b、i2c_add_driver   註冊driver的
    c、i2c_new_device   註冊client的

 

6、I2C子系統程式碼之i2c-adapter.c詳細分析

   (1)該檔案主要是用來存放s3c2410的i2c主機控制器的操作函式。

  (2)i2c主機控制器(adapter)是s5pv210的一個內建外設,所以這裡呼叫platform_driver_register()函式註冊了一個平臺匯流排驅動,其對應的裝置資訊在mach-x210.c的smdkc110_devices中,匹配是通過其中的name進行的。

  (3)s3c24xx_i2c_probe函式分析

    a、填充一個i2c_adapter結構體,並且呼叫介面去註冊之

     b、從platform_device接收硬體資訊,做必要的處理(request_mem_region & ioremap、request_irq等)

    c、對硬體做初始化(直接操作210內部I2C控制器的暫存器

 

7、I2C子系統程式碼之i2c_algorithm詳細分析

   (1)i2c->adap.algo = &s3c24xx_i2c_algorithm;

   (2)functionality
   (3)s3c24xx_i2c_doxfer

 

 

8、I2C子系統程式碼之i2c_driver與i2c_client分析

 (1)i2c_client直接來源:i2c_register_board_info

  smdkc110_machine_init
    i2c_register_board_info

  struct i2c_board_info {
    char type[I2C_NAME_SIZE]; // 裝置名
    unsigned short flags; // 屬性
    unsigned short addr; // 裝置從地址
    void *platform_data; // 裝置私有資料
    struct dev_archdata *archdata;
    #ifdef CONFIG_OF
      struct device_node *of_node;
    #endif
    int irq; // 裝置使用的IRQ號,對應CPU的EINT
  };

 

 

 (2)實現原理分析

  核心維護一個連結串列 __i2c_board_list,這個連結串列上鍊接的是I2C總線上掛接的所有硬體裝置的資訊結構體。也就是說這個連結串列維護的是一個struct i2c_board_info結構體連結串列。
真正的需要的struct i2c_client在別的地方由__i2c_board_list連結串列中的各個節點內容來另外構建生成。

  函式呼叫層次:
  i2c_add_adapter/i2c_add_numbered_adapter
    i2c_register_adapter
      i2c_scan_static_board_info
        i2c_new_device
          device_register

總結:I2C匯流排的i2c_client的提供是核心通過i2c_add_adapter/i2c_add_numbered_adapter介面呼叫時自動生成的,生成的原料是mach-x210.c中的i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

 

補充:gslX680驅動的移植實踐
  (1)原始碼獲取
  (2)原始碼加入核心中
  (3)mach檔案中新增board_info
  (4)編譯後核心去啟動
5.9.13.2、在核心配置中新增CONFIG項
  (1)定義一個巨集名,譬如CONFIG_TOUCHSCREEN_GSLX680
  (2)在程式碼中使用巨集來條件編譯
  (3)在Makefile中使用巨集來條件配置
  (4)在Kconfig專案中新增巨集的配置項
  (5)make menuconfig並選擇Y或者N