1. 程式人生 > >總結:linux驅動之I2C至少四種讀寫方法

總結:linux驅動之I2C至少四種讀寫方法

    總結在linux環境下四種讀寫I2C裝置的方法:

一:讀寫/dev/i2c-x裝置結點

    /dev/i2c-x裝置結點對應的驅動檔案為核心目錄drivers/i2c下自帶的i2c-dev.c檔案,通讀此檔案可以發現它的工作流程。

 1、通過register_chrdev註冊字元裝置結點

  2、通過class_create在sysfs下建立對應的class結點

  3、利用bus_register_nofifier對I2C匯流排新增通知鏈,在有介面卡加入或刪除時呼叫相應的處理函式

  4、通過I2C核心函式i2c_for_each_dev迴圈遍歷I2C總線上的裝置,每找到一個裝置便執行i2cdev_attach_adapter函式

  5、在i2cdev_attach_adapter函式中會首先判斷此裝置是否為介面卡,如果是,則通過device_create在/dev目錄下生成相應的結點,名稱為i2c-x,其中x為第幾個介面卡

  6、在使用者空間利用open("/dev/i2c-x",O_RDWR)操作相應結點時,會為操作此介面卡的每一個使用者建立一個i2c_client,i2c_client會通過client->adapter = adapter和file->private_data = client關聯對應的介面卡和操作檔案

  7、則在使用者空間通過read/write函式操作裝置時驅動通過struct i2c_client *client = file->private_data;獲取到介面卡結構,繼而通過呼叫I2C核心函式i2c_mater_send/i2c_master_recv,最終呼叫到具體的介面卡傳送/接收資料函式

    通過此方法操作I2C裝置時需注意在通過open開啟裝置結點後,需通過ioctl I2C_SLAVE函式設定裝置地址,之後才可通過read/write函式對裝置進行操作

二:自定義I2C裝置,並通過/dev下對應結點操作

    驅動檔案可按如下編寫:

    1、通過module_i2c_driver註冊對應的I2C驅動,此時核心會遍歷掛載在I2C總線上的裝置,通過匯流排的match方法對驅動和裝置進行匹配,匹配原則可以是1、基於裝置樹的of_driver_match_device方法,對應的結構為定義的驅動結構體是否含有of_match_table成員 2、基於id_table的匹配,對應為驅動是否定義id_table成員 3、基於名字的匹配,匹配原則為驅動的name是否和裝置的name相同 4、基於ACPI風格的匹配,使用較少

    2、當驅動和裝置匹配後會先呼叫I2C匯流排的probe函式先做一些處理,之後便會呼叫我們定義的I2C驅動的probe函式

    3、在probe函式中儲存client指標到我們自定義的裝置結構體中,如自定義為:

    struct xxx{

    struct i2c_client client;

    ... 

};

    4、通過register_chrdev註冊字元裝置,通過class_create和device_create建立/sys/和/dev/下結點(或通過mknod手工建立)

    5、在open函式中將自定義的驅動結構設定為file->private_data,方便在讀寫函式中獲取

    6、在使用者空間通過open函式開啟我們註冊的/dev/目錄下結點,read/write時便會呼叫對應的讀寫函式,在讀寫函式中會通過file->private_data獲取到自定義驅動結構,進而取到i2c_client,最終通過i2c_mater_send/i2c_master_recv或直接自己構建i2c_msg通過i2c_transfer進行傳送

三:通過DEVICE_ATTR在對應的sys裝置目錄下建立讀寫檔案

    1、還是先通過module_i2c_driver註冊對應的I2C驅動,在找到裝置後呼叫的probe函式中,只需要通過sysfs_create_files建立一組讀寫函式或sysfs_create_group建立多組操作函式

    2、編寫讀寫函式並通過DEVICE_ATTR巨集進行宣告,將函式組織為struct attribute,多組struct attribute組織為struct attribute_group並作為剛剛sysfs函式的引數

    3、使用者空間不需要通過open/read/write方法,而只需要通過echo/cat對/sys/class/裝置名稱目錄下的剛剛定義的函式進行讀寫就可以了

四:將驅動註冊為regmap,在對應的讀寫函式中使用regmap的讀寫方法

    regmap是核心3.1之後加入的特性,用於減少慢速I/O驅動上的重複邏輯,可以使驅動程式碼量減少。

    這種方法個人覺得最大的好處是那些既支援I2C又支援SPI的裝置,而在實際使用中只會使用其中一種介面,所以公共部分的讀寫函式不再通過i2c_transfer或者spi_sync_transfer這些特定於具體匯流排的操作函式,而是通過regmap提供的regmap_read/regmap_write公共函式,此函式會根據之前裝置的註冊自動選擇為是I2C或是SPI的操作,所以我們需要做的就是:

    1、通過module_i2c_driver或是module_spi_driver註冊裝置,核心會根據i2c_borad_info或者spi_board_info或者裝置樹中裝置所掛載在的匯流排自動進行I2C或者SPI的probe操作

    2、在I2C的probe函式中通過devm_regmap_init_i2c,在SPI的probe函式中通過devm_regmap_init_spi將設備註冊為regmap的對應介面,函式的第二個引數為regmap_config結構,指示了暫存器寬度和資料寬度

    3、可通過上方的二方法將設備註冊為字元裝置或三方法在/sys目錄下建立對應的操作函式

    4、在操作函式的實現中只需要通過regmap_read/regmap_write對資料進行處理就可以了

歡迎補充!