Linux I2C驅動完全分析(一)

來源:互聯網
上載者:User

 博主按:其實老早就想寫這個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的內容,如下:

/*<br /> * I2C devices<br /> */<br />static struct at24_platform_data at24c08 = {<br />.byte_len= SZ_8K / 8,<br />.page_size= 16,<br />};</p><p>static struct i2c_board_info mini2440_i2c_devs[] __initdata = {<br />{<br />I2C_BOARD_INFO("24c08", 0x50),<br />.platform_data = &at24c08,<br />},<br />};</p><p>static void __init mini2440_init(void)<br />{<br /> ... ...<br /> i2c_register_board_info(0, mini2440_i2c_devs,<br />ARRAY_SIZE(mini2440_i2c_devs));<br /> ... ...<br />}

可以看出,在mini2440的init函數中註冊了一個i2c的裝置,這個裝置我們使用了一個結構體i2c_board_info來描述。這個結構體定義在i2c.h檔案中。如下:

struct i2c_board_info {<br />chartype[I2C_NAME_SIZE];<br />unsigned shortflags;<br />unsigned shortaddr;<br />void*platform_data;<br />struct dev_archdata*archdata;<br />intirq;<br />};

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

 

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

static struct platform_device *mini2440_devices[] __initdata = {<br /> ... ...<br /> &s3c_device_i2c0,<br /> ... ...<br />};</p><p>static void __init mini2440_init(void)<br />{<br /> ... ...<br /> platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));<br /> ... ...<br />}

其中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"

static struct resource s3c_i2c_resource[] = {<br />[0] = {<br />.start = S3C_PA_IIC,<br />.end = S3C_PA_IIC + SZ_4K - 1,<br />.flags = IORESOURCE_MEM,<br />},<br />[1] = {<br />.start = IRQ_IIC,<br />.end = IRQ_IIC,<br />.flags = IORESOURCE_IRQ,<br />},<br />};</p><p>struct platform_device s3c_device_i2c0 = {<br />.name = "s3c2410-i2c",<br />#ifdef CONFIG_S3C_DEV_I2C1<br />.id = 0,<br />#else<br />.id = -1,<br />#endif<br />.num_resources = ARRAY_SIZE(s3c_i2c_resource),<br />.resource = s3c_i2c_resource,<br />};<br />

   

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()。我們實際工作中的重要一點就是要實現這個函數。

int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

 

       Adapter --> struct i2c_adapter

           這個結構體對應一個控制器。其中包含了控制器名稱,algorithm資料,控制器裝置等。

 

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

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

 int i2c_add_adapter(struct i2c_adapter *adapter)<br />int i2c_del_adapter(struct i2c_adapter *adap)

  

   *增加/刪除裝置驅動的函數int i2c_register_driver(struct module *owner, struct i2c_driver *driver)<br />void i2c_del_driver(struct i2c_driver *driver)<br />

 

    *增加/刪除i2c裝置的函數

struct i2c_client *<br />i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);<br />void i2c_unregister_device(struct i2c_client *client)

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

    *I2C傳輸、發送和接收函數int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);</p><p>int i2c_master_send(struct i2c_client *client,const char *buf ,int count);</p><p>int i2c_master_recv(struct i2c_client *client, char *buf ,int count);

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

 

(待續)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.