IIC設(shè)備驅(qū)動程序培訓(xùn)課程_第1頁
IIC設(shè)備驅(qū)動程序培訓(xùn)課程_第2頁
IIC設(shè)備驅(qū)動程序培訓(xùn)課程_第3頁
IIC設(shè)備驅(qū)動程序培訓(xùn)課程_第4頁
IIC設(shè)備驅(qū)動程序培訓(xùn)課程_第5頁
已閱讀5頁,還剩28頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、IIC設(shè)備驅(qū)動程序IIC設(shè)備是一種通過IIC總線連接的設(shè)備,由于其簡單性,被廣泛引用于電子系統(tǒng)中。在現(xiàn)代電子系統(tǒng)中,有很多的IIC設(shè)備需要進(jìn)行相互之間通信IIC總線是由PHILIPS公司開發(fā)的兩線式串行總線,用于連接微處理器和外部IIC設(shè)備。IIC設(shè)備產(chǎn)生于20世紀(jì)80年代,最初專用與音頻和視頻設(shè)備,現(xiàn)在在各種電子設(shè)備中都廣泛應(yīng)用IIC總線有兩條總線線路,一條是串行數(shù)據(jù)線(SDA),一條是串行時鐘線(SCL)。SDA負(fù)責(zé)數(shù)據(jù)傳輸,SCL負(fù)責(zé)數(shù)據(jù)傳輸?shù)臅r鐘同步。IIC設(shè)備通過這兩條總線連接到處理器的IIC總線控制器上。一種典型的設(shè)備連接如圖:與其他總線相比,IIC總線有很多重要的特點。在選擇一種

2、設(shè)備來完成特定功能時,這些特點是選擇IIC設(shè)備的重要依據(jù)。主要特點:1,每一個連接到總線的設(shè)備都可以通過唯一的設(shè)備地址單獨訪問2,串行的8位雙向數(shù)據(jù)傳輸,位速率在標(biāo)準(zhǔn)模式下可達(dá)到100kb/s;快速模式下可以達(dá)到400kb/s;告訴模式下可以達(dá)到3.4Mb/s3,總線長度最長7.6m左右4,片上濾波器可以增加抗干擾能力,保證數(shù)據(jù)的完成傳輸5,連接到一條IIC總線上的設(shè)備數(shù)量只受到最大電容400pF的限制6,它是一個多主機(jī)系統(tǒng),在一條總線上可以同時有多個主機(jī)存在,通過沖突檢測方式和延時等待防止數(shù)據(jù)不被破壞。同一時間只能有一個主機(jī)占用總線 IIC總線在傳輸數(shù)據(jù)的過程中有3種類型的信號:開

3、始信號、結(jié)束信號、和應(yīng)答信號>>開始信號(S): 當(dāng)SCL為高電平時,SDA由高電平向低電平跳變,表示將要開始傳輸數(shù)據(jù)>>結(jié)束信號(P):當(dāng)SCL為高電平時,SDA由低電平向高電平跳變,表示結(jié)束傳輸數(shù)據(jù)>>響應(yīng)信號(ACK): 從機(jī)接收到8位數(shù)據(jù)后,在第9個周期,拉低SDA電平,表示已經(jīng)收到數(shù)據(jù)。這個信號稱為應(yīng)答信號開始信號和結(jié)束信號的波形如下圖:主機(jī):IIC總線中發(fā)送命令的設(shè)備,對于ARM處理器來說,主機(jī)就是IIC控制器從機(jī):接受命令的設(shè)備 主機(jī)向從機(jī)發(fā)送數(shù)據(jù):主機(jī)通過數(shù)據(jù)線SDA向從機(jī)發(fā)送數(shù)據(jù)。當(dāng)總線空閑時,SDA和SCL信號都處于高電平。主機(jī)

4、向從機(jī)發(fā)送數(shù)據(jù)的過程:1,當(dāng)主機(jī)檢測到總線空閑時,主機(jī)發(fā)出開始信號2,主機(jī)發(fā)送8位數(shù)據(jù)。這8位數(shù)據(jù)的前7位表示從機(jī)地址,第8位表示數(shù)據(jù)的傳輸方向。這時,第8位為0,表示向從機(jī)發(fā)送數(shù)據(jù)3,被選中的從機(jī)發(fā)出響應(yīng)信號ACK4,從機(jī)傳輸一系列的字節(jié)和響應(yīng)位5,主機(jī)接受這些數(shù)據(jù),并發(fā)出結(jié)束信號P,完成本次數(shù)據(jù)傳輸 由上圖可知,IIC控制器主要是由4個寄存器來完成所有的IIC操作的。IICCON:控制是否發(fā)出ACK信號,是否開啟IIC中斷IICSTAT:IICADD:掛載到總線上的從機(jī)地址。該寄存器的7:1表示從機(jī)地址。IICADD寄存器在串行輸出使能位IICSTAT4為0時,才可以寫入;在任何

5、時候可以讀出IICDS:保存將要發(fā)送或者接收到的數(shù)據(jù)。IICCDS在串行輸出使能IICSTAT4為1時,才可以寫入;在任何時間都可以讀出 因為IIC設(shè)備種類太多,如果每一個IIC設(shè)備寫一個驅(qū)動程序,那么顯得內(nèi)核非常大。不符合軟件工程代碼復(fù)用,所以對其層次話:這里簡單的將IIC設(shè)備驅(qū)動分為設(shè)備層、總線層。理解這兩個層次的重點是理解4個數(shù)據(jù)結(jié)構(gòu),這4個數(shù)據(jù)結(jié)構(gòu)是i2c_driver、i2c_client、i2c_algorithm、i2c_adapter。i2c_driver、i2c_client屬于設(shè)備層;i2c_algorithm、i2c_adapter屬于總線型。如下圖:設(shè)備層關(guān)系

6、到實際的IIC設(shè)備,如芯片AT24C08就是一個IIC設(shè)備??偩€層包括CPU中的IIC總線控制器和控制總線通信的方法。值得注意的是:一個系統(tǒng)中可能有很多個總線層,也就是包含多個總線控制器;也可能有多個設(shè)備層,包含不同的IIC設(shè)備由IIC總線規(guī)范可知,IIC總線由兩條物理線路組成,這兩條物理線路是SDA和SCL。只要連接到SDA和SCL總線上的設(shè)備都可以叫做IIC設(shè)備。一個IIC設(shè)備由i2c_client數(shù)據(jù)結(jié)構(gòu)進(jìn)行描述:struct  i2c_clientunsigned short  flags;      &#

7、160;                 /標(biāo)志位      unsigned short  addr;  /設(shè)備的地址,低7位為芯片地址char nameI2C_NAME_SIZE;   /設(shè)備的名稱,最大為20個字節(jié)struct  i2c_adapter *adapter;/依附的適配器i2c_adapter,適配器指明所屬的總線st

8、ruct  i2c_driver *driver;/指向設(shè)備對應(yīng)的驅(qū)動程序struct device  dev;/設(shè)備結(jié)構(gòu)體int irq;/設(shè)備申請的中斷號struct list_head  list;/連接到總線上的所有設(shè)備struct list_head detected;/已經(jīng)被發(fā)現(xiàn)的設(shè)備鏈表struct completionreleased;/是否已經(jīng)釋放的完成量; 設(shè)備結(jié)構(gòu)體i2c_client中addr的低8位表示設(shè)備地址。設(shè)備地址由讀寫位、器件類型和自定義地址組成,如下圖:第7位是R/W位,0表示寫,2表示讀,所以I2C設(shè)備通常有兩個地址

9、,即讀地址和寫地址類型器件由中間4位組成,這是由半導(dǎo)體公司生產(chǎn)的時候就已經(jīng)固化了。自定義類型由低3位組成。由用戶自己設(shè)置,通常的做法如EEPROM這些器件是由外部I芯片的3個引腳所組合電平?jīng)Q定的(A0,A1,A2)。A0,A1,A2 就是自定義的地址碼。自定義的地址碼只能表示8個地址,所以同一IIC總線上同一型號的芯片最多只能掛載8個。AT24C08的自定義地址碼如圖:A0,A1,A2接低電平,所以自定義地址碼為0;如果在兩個不同IIC總線上掛接了兩塊類型和地址相同的芯片,那么這兩塊芯片的地址相同。這顯然是地址沖突,解決的辦法是為總線適配器指定一個ID號,那么新的芯片地址就由總線適配器的ID和

10、設(shè)備地址組成除了地址之外,IIC設(shè)備還有一些重要的注意事項:1,i2c_client數(shù)據(jù)結(jié)構(gòu)是描述IIC設(shè)備的“模板”,驅(qū)動程序的設(shè)備結(jié)構(gòu)中應(yīng)包含該結(jié)構(gòu)2,adapter指向設(shè)備連接的總線適配器,系統(tǒng)可能有多個總線適配器。內(nèi)核中靜態(tài)指針數(shù)組adapters記錄所有已經(jīng)注冊的總線適配器設(shè)備3,driver是指向設(shè)備驅(qū)動程序,這個驅(qū)動程序是在系統(tǒng)檢測到設(shè)備存在時賦值的 IIC設(shè)備驅(qū)動     i2c_driver:struct  i2c_driverint id;      &#

11、160;                  /驅(qū)動標(biāo)識IDunsigned int class;               /驅(qū)動的類型int (*attach_adapter)(struct i2c_adapter *);     &#

12、160;       /當(dāng)檢測到適配器時調(diào)用的函數(shù)       int (*detach_adapter)(struct i2c_adapter*);              /卸載適配器時調(diào)用的函數(shù)int (*detach_client)(struct i2c_client *)   _deprecated; &#

13、160;           /卸載設(shè)備時調(diào)用的函數(shù)       /以下是一種新類型驅(qū)動需要的函數(shù),這些函數(shù)支持IIC設(shè)備動態(tài)插入和拔出。如果不想支持只實現(xiàn)上面3個。要不實現(xiàn)上面3個。要么實現(xiàn)下面5個。不能同時定義       int  (*probe)(struct i2c_client *,const struct  i2c_device_id *);&

14、#160;             /新類型設(shè)備探測函數(shù)       int (*remove)(struct i2c_client *);                   /新類型設(shè)備的移除函數(shù)   &#

15、160;   void (*shutdown)(struct i2c_client *);              /關(guān)閉IIC設(shè)備        int (*suspend)(struct  i2c_client *,pm_messge_t mesg);         &#

16、160; /掛起IIC設(shè)備        int (*resume)(struct  i2c_client *);                               /恢復(fù)IIC設(shè)備  &#

17、160;     int (*command)(struct i2c_client *client,unsigned int cmd,void *arg);        /使用命令使設(shè)備完成特殊的功能。類似ioctl()函數(shù)        struct devcie_driver  driver;         &

18、#160;               /設(shè)備驅(qū)動結(jié)構(gòu)體         const struct  i2c_device_id *id_table;                  &#

19、160;    /設(shè)備ID表          int (*detect)(struct i2c_client *,int  kind,struct  i2c_board_info *);          /自動探測設(shè)備的回調(diào)函數(shù)         const  struct i

20、2c_client_address_data          *address_data;                 /設(shè)備所在的地址范圍         struct  list_head    clients;

21、0;                   /指向驅(qū)動支持的設(shè)備;結(jié)構(gòu)體i2c_driver和i2c_client的關(guān)系較為簡單,其中i2c_driver表示一個IIC設(shè)備驅(qū)動,i2c_client表示一個IIC設(shè)備。關(guān)系如下圖:IIC總線適配器就是一個IIC總線控制器,在物理上連接若干個IIC設(shè)備。IIC總線適配器本質(zhì)上是一個物理設(shè)備,其主要功能是完成IIC總線控制器相關(guān)的數(shù)據(jù)通信:struct i2c_adapte

22、r        struct module *owner;                        /模塊計數(shù)        unsigned  int id;    &#

23、160;                             /alogorithm的類型,定義于i2c_id.h中        unsigned   int  class;   &#

24、160;                       /允許探測的驅(qū)動類型        const struct i2c_algorithm *algo;         /指向適配器的驅(qū)動程序   

25、;     void *algo_data;                                  /指向適配器的私有數(shù)據(jù),根據(jù)不同的情況使用方法不同     

26、0;  int (*client_register)(struct  i2c_client *);          /設(shè)備client注冊時調(diào)用        int (*client_unregister(struct  i2c_client *);       /設(shè)備client注銷時調(diào)用    

27、60;   u8 level;                                              

28、;                   struct  mutex  bus_lock;                          

29、   /對總線進(jìn)行操作時,將獲得總線鎖        struct  mutex  clist_lock ;                            /鏈表操作的互斥鎖   &

30、#160;    int timeout;                                            

31、      /超時int retries;                                          &#

32、160;          /重試次數(shù)       struct device dev;                              &

33、#160;           /指向 適配器的設(shè)備結(jié)構(gòu)體       int  nr ;                            &#

34、160;                                    struct  list_head      clients;    

35、                        /連接總線上的設(shè)備的鏈表        char name48;               

36、0;                              /適配器名稱        struct completion     dev_released;   &

37、#160;           /用于同步的完成量;每一個適配器對應(yīng)一個驅(qū)動程序,該驅(qū)動程序描述了適配器與設(shè)備之間的通信方法:struct  i2c_algorithm         int  (*master_xfer)(struct  i2c_adapter *adap,  struct  i2c_msg *msg, int num);  &

38、#160;           /傳輸函數(shù)指針,指向?qū)崿F(xiàn)IIC總線通信協(xié)議的函數(shù),用來確定適配器支持那些傳輸類型         int  (*smbus_xfer)(struct  i2c_adapter *adap, u16  addr, unsigned  short flags, char  read_write, u8 command, int size,

39、union  i2c_smbus_data  *data);    /smbus方式傳輸函數(shù)指針,指向?qū)崿F(xiàn)SMBus總線通信協(xié)議的函數(shù)。SMBus和IIC之間可以通過軟件方式兼容,所以這里提供了一個函數(shù),但是一般都賦值為NULL         u32  (*functionality)(struct  i2c_adapter *);         

40、60;         /返回適配器支持的功能; IIC設(shè)備驅(qū)動程序大致可以分為設(shè)備層和總線層。設(shè)備層包括一個重要的數(shù)據(jù)結(jié)構(gòu),i2c_client??偩€層包括兩個重要的數(shù)據(jù)結(jié)構(gòu),分別是i2c_adapter和i2c_algorithm。一個i2c_algorithm結(jié)構(gòu)表示適配器對應(yīng)的傳輸數(shù)據(jù)方法。3個數(shù)據(jù)結(jié)構(gòu)關(guān)系: IIC設(shè)備層次結(jié)構(gòu)較為簡單,但是寫IIC設(shè)備驅(qū)動程序卻相當(dāng)復(fù)雜。IIC設(shè)備驅(qū)動程序的步驟:IIC子系統(tǒng):IIC子系統(tǒng)是作為模塊加載到系統(tǒng)中的。初始化函數(shù):static int _i

41、nit i2c_init(void)    int retval;            /返回值,成功0,錯誤返回負(fù)值    retval = bus_register(&i2c_bus_type);       /注冊一條IIC的BUS總線    if (retval)     

42、0;  return retval;    retval = class_register(&i2c_adapter_class);       /注冊適配器類,用于實現(xiàn)sys文件系統(tǒng)的部分功能    if (retval)        goto bus_err;    retval = i2c_add_driver(&dummy_driver); 

43、              /將一個空驅(qū)動程序注冊到IIC總線中    if (retval)        goto class_err;    return 0;class_err:    class_unregister(&i2c_adapter_class);   

44、0;                            /類注銷bus_err:    bus_unregister(&i2c_bus_type);           

45、0;                              /總線注銷    return retval; struct bus_type i2c_bus_type =     .name     

46、;   = "i2c",    .dev_attrs    = i2c_dev_attrs,    .match        = i2c_device_match,    .uevent        = i2c_device_uevent,    .probe  

47、     = i2c_device_probe,    .remove        = i2c_device_remove,    .shutdown    = i2c_device_shutdown,    .suspend    = i2c_device_suspend,    .resume 

48、0;      = i2c_device_resume,;static struct class i2c_adapter_class =     .owner            = THIS_MODULE,    .name            = "i2c-adapter", &#

49、160;  .dev_attrs        = i2c_adapter_attrs,;static struct i2c_driver dummy_driver =     .    = "dummy",    .probe        = dummy_probe,    .remove &

50、#160;      = dummy_remove,    .id_table    = dummy_id,; IIC子系統(tǒng)退出函數(shù):static void _exit i2c_exit(void)    i2c_del_driver(&dummy_driver);        /注銷IIC設(shè)備驅(qū)動程序,主要功能是去掉總線中的該設(shè)備驅(qū)動程序    

51、class_unregister(&i2c_adapter_class);              /注銷適配器類    bus_unregister(&i2c_bus_type);                    

52、   /注銷I2C總線 適配器驅(qū)動程序是IIC設(shè)備驅(qū)動程序需要實現(xiàn)的主要驅(qū)動程序,這個驅(qū)動程序需要根據(jù)具體的適配器硬件來編寫。I2c_adapter結(jié)構(gòu)體為描述各種IIC適配器提供了“模板",它定義了注冊總線上所有設(shè)備的clients鏈表、指向具體IIC適配器的總線通信方法I2c_algorithm的algo指針、實現(xiàn)i2c總線的操作原子性的lock信號量。但i2c_adapter結(jié)構(gòu)體只是所有適配器的共有屬性,并不能代表所有類型的適配器 s3c2440對應(yīng)的適配器為:struct s3c24xx_i2c     

53、spinlock_t        lock;           /lock自旋鎖    wait_queue_head_t    wait;       /等待隊列頭。由于IIC設(shè)備是低速設(shè)備,所以可以采取“阻塞-中斷”的驅(qū)動模型,即讀寫i2c設(shè)備的用戶程序在IIC設(shè)備操作期間進(jìn)入阻塞狀態(tài),待IIC操作完成后,總線

54、適配器將引發(fā)中斷,再將相應(yīng)的中斷處理函數(shù)中喚醒受阻的用戶進(jìn)程。該隊列用來放阻塞的進(jìn)程    unsigned int        suspended:1;         /設(shè)備是否掛起    struct i2c_msg        *msg;       /從適配器到設(shè)備

55、一次傳輸?shù)膯挝唬眠@個結(jié)構(gòu)體將數(shù)據(jù)包裝起來便于操作 ,    unsigned int        msg_num;       /表示消息的個數(shù)    unsigned int        msg_idx;            /表示第幾個消

56、息。當(dāng)完成一個消息后,該值增加    unsigned int        msg_ptr;            /總是指向當(dāng)前交互中要傳送、接受的下一個字節(jié),在i2c_msg.buf中的偏移量位置    unsigned int        tx_setup;   

57、60;       /表示寫IIC設(shè)備寄存器的一個時間,這里被設(shè)置為50ms    unsigned int        irq;                         /適配器申請的中斷號

58、0;   enum s3c24xx_i2c_state    state;      /表示IIC設(shè)備目前的狀態(tài)    unsigned long        clkrate;             /時鐘速率    void _iomem &#

59、160;      *regs;            /IIC設(shè)備寄存器地址    struct clk        *clk;                   

60、    /對應(yīng)的時鐘    struct device        *dev;                 /適配器對應(yīng)的設(shè)備結(jié)構(gòu)體    struct resource        *ioarea;  

61、;          /適配器的資源    struct i2c_adapter    adap;                  /適配器主體結(jié)構(gòu)體#ifdef CONFIG_CPU_FREQ    struct notifier_block&#

62、160;   freq_transition;#endif;enum s3c24xx_i2c_state     STATE_IDLE,    STATE_START,    STATE_READ,    STATE_WRITE,    STATE_STOP; struct  i2c_msg         _u16 

63、  addr;                                /IIC設(shè)備地址。 這個字段說明一個適配器在獲得總線控制權(quán)后,可以與多個IIC設(shè)備進(jìn)行交互。         _u16&#

64、160;  flags;                                /消息類型標(biāo)志 。      #define  I2C_M_TEN    

65、0;    0x0010        /這是有10位地址芯片#define  I2C_M_RD            0x0001       /表示從 從機(jī)到主機(jī)讀數(shù)據(jù)#define  I2C_M_NOSTART       0x4000

66、0;                 / FUNC_PROTOCOL_MANLING協(xié)議的相關(guān)標(biāo)志#define  I2C_M_REV_DIR_ADDR   0x2000          /FUNC_PROTOCOL_MANLING協(xié)議的相關(guān)標(biāo)志#define  I2C_M_IGNORE_NAK 

67、        0x1000         /FUNC_PROTOCOL_MANLING協(xié)議的相關(guān)標(biāo)志#define  I2C_M_NO_RD_ACK           0x0800         /FUNC_PROTOCOL_MANLING協(xié)議的相關(guān)標(biāo)

68、志#define  I2C_M_RECV_LEN            0x0400          /第一次接收的字節(jié)長度        _u16    len;          &#

69、160;                                       /消息字節(jié)長度        _u8  &#

70、160;    * buf;                                             &

71、#160; /指向消息數(shù)據(jù)的緩沖區(qū); 當(dāng)拿到一塊新的電路板,并研究了響應(yīng)的IIC適配器之后,就應(yīng)該使用內(nèi)核提供的框架函數(shù)向IIC子系統(tǒng)添加一個新的適配器過程:1,分配一個IIC適配器,并初始化相應(yīng)的變量2,使用i2c_add_adapter()函數(shù)向IIC子系統(tǒng)添加適配器結(jié)構(gòu)體i2c_adapter。這個結(jié)構(gòu)體已經(jīng)在第一步初始化了:int i2c_add_adapter(struct i2c_adapter *adapter)    int    id, res = 0;retry:    if

72、 (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) = 0)           /存放分配ID號的內(nèi)存        return -ENOMEM;                    

73、60;      /內(nèi)存分配失敗    mutex_lock(&core_lock);           /鎖定內(nèi)核鎖    /* "above" here means "above or equal to", sigh */    res = idr_get_new_above(&i2c_adapt

74、er_idr, adapter,                _i2c_first_dynamic_bus_num, &id);            /分配ID號,并將ID號和指針關(guān)聯(lián)    mutex_unlock(&core_lock);      

75、60;    /釋放內(nèi)核鎖    if (res < 0)         if (res = -EAGAIN)            goto retry;                   

76、;                                                  /分配失

77、敗,重試        return res;        adapter->nr = id;    return i2c_register_adapter(adapter);                      

78、/ 注冊適配器設(shè)備 關(guān)于IDR機(jī)制,請參考:ack/archive/2012/09/15/2686557.htmlstatic DEFINE_IDR(i2c_adapter_idr);通過ID號獲得適配器指針:struct i2c_adapter* i2c_get_adapter(int id)    struct i2c_adapter *adapter;                

79、0; /適配器指針    mutex_lock(&core_lock);           /鎖定內(nèi)核鎖    adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);          /通過ID號,查詢適配器指針    if (

80、adapter && !try_module_get(adapter->owner)              /適配器引用計數(shù)+1        adapter = NULL;    mutex_unlock(&core_lock);         

81、60;                  /釋放內(nèi)核鎖    return adapter;適配器卸載函數(shù):主要任務(wù):注銷適配器的數(shù)據(jù)結(jié)構(gòu),刪除總線上的所有設(shè)備的I2c_client數(shù)據(jù)結(jié)構(gòu)和對應(yīng)的i2c_driver驅(qū)動程序,并減少其代表總線上所有設(shè)備的相應(yīng)驅(qū)動程序數(shù)據(jù)結(jié)構(gòu)的引用計數(shù)(如果到達(dá)0,則卸載設(shè)備驅(qū)動程序):int i2c_del_adapter(struct i2c_adapter

82、*adap)    struct i2c_client *client, *_n;    int res = 0;    mutex_lock(&core_lock);    /* First make sure that this adapter was ever added */    if (idr_find(&i2c_adapter_idr, adap->nr) != adap)    

83、                       /查找要卸載的適配器        pr_debug("i2c-core: attempting to delete unregistered "           

84、60; "adapter %sn", adap->name);        res = -EINVAL;        goto out_unlock;        /* Tell drivers about this removal */    res = bus_for_each_drv(&i2c_bus_type, NULL, adap,

85、60;                  i2c_do_del_adapter);    if (res)        goto out_unlock;    /* detach any active clients. This must be done first, because     * it ca

86、n fail; in which case we give up. */    list_for_each_entry_safe_reverse(client, _n, &adap->clients, list)         struct i2c_driver    *driver;        driver = client->driver;     

87、;   /* new style, follow standard driver model */        if (!driver | is_newstyle_driver(driver)             i2c_unregister_device(client);            continue; 

88、60;              /* legacy drivers create and remove clients themselves */        if (res = driver->detach_client(client)             dev_err(&adap->dev, "detac

89、h_client failed for client "                "%s at address 0x%02xn", client->name,                client->addr);         

90、60;  goto out_unlock;                /* clean up the sysfs representation */    init_completion(&adap->dev_released);    device_unregister(&adap->dev);      

91、0;                      設(shè)備注銷    /* wait for sysfs to drop all references */    wait_for_completion(&adap->dev_released);    /* free bus id */&#

92、160;   idr_remove(&i2c_adapter_idr, adap->nr);                      /刪除IDR,ID號    dev_dbg(&adap->dev, "adapter %s unregisteredn", adap->name);&

93、#160;   /* Clear the device structure in case this adapter is ever going to be       added again */    memset(&adap->dev, 0, sizeof(adap->dev); out_unlock:    mutex_unlock(&core_lock);    return res;II

94、C總線通信方法s3c24xx_i2c_algorithm結(jié)構(gòu)體:static const struct i2c_algorithm s3c24xx_i2c_algorithm =     .master_xfer        = s3c24xx_i2c_xfer,    .functionality        = s3c24xx_i2c_func,;這里只實現(xiàn)了IIC總線通信協(xié)議通信方法因不同的適配器有所不同,

95、要跟據(jù)具體的硬件來實現(xiàn)協(xié)議支持函數(shù)s3c24xx_i2c_func()該函數(shù)返回總線支持的協(xié)議,如I2C_FUNC_I2C、I2C_FUNC_SMBUS_EMUL、I2C_FUNC_PROTOCOL_MANGLING協(xié)議:static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)    return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;傳輸函數(shù)s3c24xx_i2c_xfer():static int s3c24xx_i2c_

96、xfer(struct i2c_adapter *adap,            struct i2c_msg *msgs, int num)    struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;    /從適配器的私有數(shù)據(jù)中獲得適配器s3c24xx_i2c結(jié)構(gòu)體    int retry;   &

97、#160;                                                 &

98、#160;                                       /傳輸錯誤重發(fā)次數(shù)    int ret;     

99、                                                  

100、                                         /返回值    for (retry = 0; retry < adap->

101、retries; retry+)         ret = s3c24xx_i2c_doxfer(i2c, msgs, num);                                  

102、     /傳輸?shù)絀IC設(shè)備的具體函數(shù)        if (ret != -EAGAIN)            return ret;        dev_dbg(i2c->dev, "Retrying transmission (%d)n", retry);     

103、;           /重試信息        udelay(100);                              

104、60;                                                 

105、60;   /延時100us        return -EREMOTEIO;                                    

106、0;                                  / I/O錯誤真正的傳輸函數(shù):static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,      

107、;            struct i2c_msg *msgs, int num)    unsigned long timeout;                            

108、60;                                                 

109、60; /定義一個傳輸超時時間    int ret;                                           

110、                                                  

111、             /返回值,傳輸消息的個數(shù)    if (i2c->suspended)                             

112、                                                  

113、       /如果適配器處于掛起省電狀態(tài),則返回        return -EIO;    ret = s3c24xx_i2c_set_master(i2c);                       

114、0;                                      /將適配器設(shè)為主機(jī)發(fā)送狀態(tài),判斷總線忙閑狀態(tài)    if (ret != 0)    &#

115、160;                                                 &#

116、160;                                            /如果總線繁忙,則傳輸失敗     

117、;   dev_err(i2c->dev, "cannot get bus (error %d)n", ret);        ret = -EAGAIN;        goto out;        spin_lock_irq(&i2c->lock);        &#

118、160;                                    /操作適配器的自旋鎖鎖定,每次只允許一個進(jìn)程傳輸數(shù)據(jù),其他進(jìn)程無法獲得總線    i2c->msg   

119、  = msgs;                                               

120、0;     /傳輸?shù)南⒅羔?#160;   i2c->msg_num = num;                                     &#

121、160;           /傳輸?shù)南€數(shù)    i2c->msg_ptr = 0;                               &#

122、160;                         /當(dāng)前要傳輸?shù)淖止?jié)在消息中的偏移    i2c->msg_idx = 0;                

123、                                         /消息數(shù)組的索引    i2c->state   = STAT

124、E_START;    s3c24xx_i2c_enable_irq(i2c);                                      /啟動適配器中斷信號,允許適配器發(fā)出中斷&#

125、160;   s3c24xx_i2c_message_start(i2c, msgs);                     /當(dāng)調(diào)用該函數(shù)啟動 數(shù)據(jù)發(fā)送后,當(dāng)前進(jìn)程進(jìn)入睡眠狀態(tài),等待中斷到來,所以通過wait_event_timeout()函數(shù)將自己掛起到s3c24xx_i2c.wait等待隊列上,直到等待的條件"i2c->msg_num = 0"

126、;為真,或者5s超時后才能喚醒。注意一次i2c操作可能要涉及多個字節(jié),只有第一個字節(jié)發(fā)送是在當(dāng)前進(jìn)程的文件系統(tǒng)操作執(zhí)行流中進(jìn)行的,該字節(jié)操作的完成及后繼字節(jié)的寫入都由中斷處理程序來完成。在此期間當(dāng)前進(jìn)程掛起在s3c24xx_i2c.wait等待隊列上    spin_unlock_irq(&i2c->lock);    timeout = wait_event_timeout(i2c->wait, i2c->msg_num = 0, HZ * 5);    ret = i2c-&

127、gt;msg_idx;    /* having these next two as dev_err() makes life very     * noisy when doing an i2cdetect */    if (timeout = 0)                     &#

128、160;                                            /在規(guī)定的時間內(nèi),沒有成功的寫入數(shù)據(jù)        dev_dbg(i2c->dev, "timeoutn");    else if (ret != num)                              

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論