欧美亚洲一区二区三区,午夜欧美艳情视频免费看,欧美XXXXX又粗又大,国精品产露脸偷拍视频

技術(shù)文摘

Linux I2C驅(qū)動(dòng)分析(一)——I2C架構(gòu)和總線驅(qū)動(dòng)






一、I2C總線原理

I2C是一種常用的串行總線,由串行數(shù)據(jù)線SDA 和串線時(shí)鐘線SCL組成。I2C是一種多主機(jī)控制總線,它和USB總線不同,USB是基于master-slave機(jī)制,任何設(shè)備的通信必須由主機(jī)發(fā)起才可以,而 I2C 是基于multi master機(jī)制,一條總線上可允許多個(gè)master。

系統(tǒng)的I2C模塊分為I2C總線控制器和I2C設(shè)備。I2C 總線控制器是CPU提供的控制I2C總線接口,它控制I2C總線的協(xié)議、仲裁、時(shí)序。I2C設(shè)備是指通過(guò)I2C總線與CPU相連的設(shè)備,如EEPROM。使用I2C通信時(shí)必須指定主從設(shè)備。一般來(lái)說(shuō),I2C總線控制器被配置成主設(shè)備,與總線相連的I2C設(shè)備如AT24C02作為從設(shè)備。


1.1、IIC讀寫原理

IIC總線的開(kāi)始/停止信號(hào)如圖1所示。開(kāi)始信號(hào)為:時(shí)鐘信號(hào)線SCL為高電平,數(shù)據(jù)線SDA從高變低。停止信號(hào)為:時(shí)鐘信號(hào)線SCL為高電平,數(shù)據(jù)線SDA從低變高。

IC讀寫原理圖.gif


圖1 IIC Start-Stop Signal






1.2、IIC總線Byte Write

IIC總線寫數(shù)據(jù)分幾種格式,如字節(jié)寫和頁(yè)寫。

字節(jié)寫傳送格式如圖2所示。開(kāi)始信號(hào)之后,總線開(kāi)始發(fā)數(shù)據(jù),第一個(gè)Byte是IIC的設(shè)備地址,第二個(gè)Byte是設(shè)備內(nèi)的地址(如EEPROM中具體的某個(gè)物理地址),然后就是要傳送的真正的數(shù)據(jù)DATA。

NOTE:IIC 總線在傳送每個(gè)Byte后,都會(huì)從IIC總線上的接收設(shè)備得到一個(gè)ACK信號(hào)來(lái)確認(rèn)接收到了數(shù)據(jù)。其中,第一個(gè)Byte的設(shè)備地址中,前7位是地址碼,第8位是方向位(“0”為發(fā)送,“1”為接收)。IIC的中斷信號(hào)有:ACK,Start,Stop。


ic總線圖.gif


Write功能的實(shí)際實(shí)現(xiàn)原理如圖3所示:

(1)設(shè)置GPIO的相關(guān)引腳為IIC輸出;

(2)設(shè)置IIC(打開(kāi)ACK,打開(kāi)IIC中斷,設(shè)置CLK等);

(3)設(shè)備地址賦給IICDS ,并設(shè)置IICSTAT,啟動(dòng)IIC發(fā)送設(shè)備地址出去;從而找到相應(yīng)的設(shè)備即IIC總線上的設(shè)備。

(4)第一個(gè)Byte的設(shè)備地址發(fā)送后,從EEPROM得到ACK信號(hào),此信號(hào)觸發(fā)中斷;

(5)在中斷處理函數(shù)中把第二個(gè)Byte(設(shè)備內(nèi)地址)發(fā)送出去;發(fā)送之后,接收到ACK又觸發(fā)中斷;

(6)中斷處理函數(shù)把第三個(gè)Byte(真正的數(shù)據(jù))發(fā)送到設(shè)備中。

(7)發(fā)送之后同樣接收到ACK并觸發(fā)中斷,中斷處理函數(shù)判斷,發(fā)現(xiàn)數(shù)據(jù)傳送完畢。

(8)IIC Stop信號(hào),關(guān)IIC中斷,置位各寄存器。


IC圖3.gif


圖3 IIC Write Operation

NOTE:對(duì)于EEPROM,IICDS寄存器發(fā)送的數(shù)據(jù)會(huì)先放在Ring buffer中,當(dāng)其收到stop信號(hào)時(shí),開(kāi)始實(shí)際寫入EEPROM中。在實(shí)際寫的過(guò)程中,EEPROM不響應(yīng)從CPU來(lái)的信號(hào),直到寫完才會(huì)響應(yīng),因而有一段延遲代碼。在page write時(shí),注意一定要有延時(shí)!

NOTE:數(shù)據(jù)先寫到EEPROM的ring buffer中,收到Stop信號(hào)時(shí),開(kāi)始實(shí)際地把數(shù)據(jù)寫入EEPROM,這時(shí)不響應(yīng)任何輸入。即這時(shí)Write函數(shù)中后面的延時(shí)中,向其發(fā)slvaddr時(shí),不會(huì)得到ACK,直到數(shù)據(jù)寫完時(shí),才會(huì)收到ACK。







1.3IIC總線Random Read

IIC總線讀數(shù)據(jù)為Current Address Read,Random Read,Sequential Read

IIC 總線Random Read傳送格式如圖4所示。開(kāi)始信號(hào)后,CPU開(kāi)始寫第一個(gè)Byte(IIC的設(shè)備地址),第二個(gè)Byte是設(shè)備內(nèi)的地址(此地址保存在設(shè)備中)。然后開(kāi)始讀過(guò)程:發(fā)送設(shè)備地址找到IIC設(shè)備,然后就開(kāi)始讀數(shù)據(jù)。類似寫過(guò)程,CPU讀一個(gè)byte的實(shí)際數(shù)據(jù)后,CPU向IIC的EEPROM 發(fā)ACK,ACK觸發(fā)中斷。讀數(shù)據(jù)也在中斷程序中進(jìn)行。


ic圖4.gif


圖4 IIC Random Read Operation






二、I2C架構(gòu)概述

在linux中,I2C驅(qū)動(dòng)架構(gòu)如下所示:

圖5.gif


圖5 I2C驅(qū)動(dòng)架構(gòu)1

Linux中I2C體系結(jié)構(gòu)如下圖所示(圖片來(lái)源于網(wǎng)絡(luò))。圖中用分割線分成了三個(gè)層次:用戶空間(也就是應(yīng)用程序),內(nèi)核(也就是驅(qū)動(dòng)部分)和硬件(也就是實(shí)際物理設(shè)備)。我們現(xiàn)在就是要研究中間那一層。






2.1I2C驅(qū)動(dòng)概述

Linux的I2C驅(qū)動(dòng)結(jié)構(gòu)可分為3個(gè)部分:
a、 I2C核心
I2C 核心提供了I2C總線驅(qū)動(dòng)和設(shè)備驅(qū)動(dòng)的注冊(cè)、注銷方法,I2C通信方法(即“algorithm”),與具體適配器無(wú)關(guān)的代碼以及探測(cè)設(shè)備、檢測(cè)設(shè)備地址等。i2c-core.c中的核心驅(qū)動(dòng)程序可管理多個(gè)I2C總線適配器(控制器)和多個(gè)I2C從設(shè)備。每個(gè)I2C從設(shè)備驅(qū)動(dòng)都能找到和它相連的I2C總線適配器。

b、I2C總線驅(qū)動(dòng)
I2C總線驅(qū)動(dòng)主要包括I2C適配器結(jié)構(gòu)i2c_adapter和I2C適配器的algorithm數(shù)據(jù)結(jié)構(gòu)。
通過(guò)I2C總線驅(qū)動(dòng)的代碼,可控制I2C適配器以主控方式產(chǎn)生開(kāi)始位、停止位、讀寫周期,以及以從設(shè)備方式被讀寫、產(chǎn)生ACK等。

c、I2C設(shè)備驅(qū)動(dòng)
I2C設(shè)備驅(qū)動(dòng)是對(duì)I2C設(shè)備端的實(shí)現(xiàn),設(shè)備一般掛接在受CPU控制的I2C適配器上,通過(guò)I2C適配器與CPU交換數(shù)據(jù)。
I2C設(shè)備驅(qū)動(dòng)主要包括數(shù)據(jù)結(jié)構(gòu)i2c_driver和i2c_client。


圖6.gif


圖6 I2C驅(qū)動(dòng)架構(gòu)2






三、I2C代碼在內(nèi)核中的結(jié)構(gòu)

3.1  I2C驅(qū)動(dòng)調(diào)用關(guān)系

內(nèi)核中對(duì)于I2C定義了4種結(jié)構(gòu):

1)i2c_adapter—I2C總線適配器。即為CPU中的I2C總線控制器。

2)i2c_algorithm—I2C總線通信傳輸算法,管理I2C總線控制器,實(shí)現(xiàn)I2C總線上數(shù)據(jù)的發(fā)送和接收等操作。

3)i2c_client—掛載在I2C總線上的I2C設(shè)備的驅(qū)動(dòng)程序。

4)i2c_driver—用于管理I2C的驅(qū)動(dòng)程序,它對(duì)應(yīng)I2C的設(shè)備節(jié)點(diǎn)。

這4種結(jié)構(gòu)的定義見(jiàn)include/linux/i2c.h文件。

對(duì)于i2c_driver和i2c_client,i2c_driver對(duì)應(yīng)一套驅(qū)動(dòng)方法,是純粹的用于輔助作用的數(shù)據(jù)結(jié)構(gòu),它不對(duì)應(yīng)于任何的物理實(shí)體。        

i2c_client對(duì)應(yīng)于真實(shí)的物理設(shè)備,每個(gè)I2C設(shè)備都需要一個(gè)i2c_client來(lái)描述。i2c_client 一般被包含在i2c字符設(shè)備的私有信息結(jié)構(gòu)體中。i2c_driver 與i2c_client發(fā)生關(guān)聯(lián)的時(shí)刻在i2c_driver的attach_adapter()函數(shù)被運(yùn)行時(shí)。attach_adapter()會(huì)探測(cè)物理設(shè)備,當(dāng)確定一個(gè)client存在時(shí),把該client使用的i2c_client數(shù)據(jù)結(jié)構(gòu)的adapter指針指向?qū)?yīng)的i2c_adapter,driver指針指向該i2c_driver,并會(huì)調(diào)用i2c_adapter的client_register()函數(shù)。相反的過(guò)程發(fā)生在i2c_driver 的detach_client()函數(shù)被調(diào)用的時(shí)候。

對(duì)于i2c_adpater 與i2c_client,與I2C硬件體系中適配器和設(shè)備的關(guān)系一致,即i2c_client依附于i2c_adpater。由于一個(gè)適配器上可以連接多個(gè)I2C設(shè)備,所以一個(gè)i2c_adpater也可以被多個(gè)i2c_client依附,i2c_adpater中包括依附于它的i2c_client的鏈表。

i2c.h文件中除定義上述4個(gè)重要結(jié)構(gòu)之外,還定義了一個(gè)非常重要的結(jié)構(gòu)體:i2c_msg,其定義如下:

1.   struct i2c_msg {

2.          __u16 addr; /* slave address*/

3.          __u16 flags;

4.   #define I2C_M_TEN 0x0010 /* this is a ten bit chip address */

5.   #define I2C_M_RD 0x0001 /* read data, from slave to master */

6.   #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */

7.   #define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */

8.   #define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */

9.   #define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */

10.  #define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */

11.          __u16 len; /* msg length */

12.          __u8 *buf; /* pointer to msg data */

13.  };

它是實(shí)際傳輸?shù)臄?shù)據(jù),其中包括了slave address、數(shù)據(jù)長(zhǎng)度和實(shí)際的數(shù)據(jù)。







3.2  內(nèi)核中的I2C驅(qū)動(dòng)

Linux內(nèi)核源碼的drivers目錄下有個(gè)i2c目錄,其中包含如下文件和文件夾:

a、i2c-core.c

這個(gè)文件實(shí)現(xiàn)了I2C核心的功能以及/proc/bus/i2c*接口。

b、i2c-dev.c

實(shí)現(xiàn)了I2C適配器設(shè)備文件的功能,每一個(gè)I2C適配器都被分配一個(gè)設(shè)備。通過(guò)適配器訪問(wèn)設(shè)備時(shí)的主設(shè)備號(hào)都為89,次設(shè)備號(hào)為0~255。應(yīng)用程序通過(guò)“i2c-%d” (i2c-0, i2c-1, ..., i2c-10, ...)文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等來(lái)訪問(wèn)這個(gè)設(shè)備。

 i2c-dev.c并沒(méi)有針對(duì)特定的設(shè)備而設(shè)計(jì),只是提供了通用的read()、write()和ioctl()等接口,應(yīng)用層可以借用這些接口訪問(wèn)掛接在適配器上I2C設(shè)備的存儲(chǔ)空間或寄存器,并控制I2C設(shè)備的工作方式。

c、chips文件夾

此目錄中包含了一些特定的I2C設(shè)備驅(qū)動(dòng),如RTC實(shí)時(shí)鐘芯片驅(qū)動(dòng)和I2C接口的EEPROM驅(qū)動(dòng)等。

d、busses文件夾

此目錄中包含了一些I2C總線的驅(qū)動(dòng),如S3C2410的I2C控制器驅(qū)動(dòng)為i2c-s3c2410.c。

e、algos文件夾

實(shí)現(xiàn)了一些I2C總線適配器的algorithm。

i2c-core.c文件不需要修改,其主要實(shí)現(xiàn)的函數(shù)有:

1)adapter和client相關(guān)操作

     1.   int i2c_add_adapter(struct i2c_adapter *adap); //增加adapter

     2.   int i2c_del_adapter(struct i2c_adapter *adap);

     3.   int i2c_register_driver(struct module *, struct i2c_driver *); //增加驅(qū)動(dòng) (i2c_add_driver)

     4.   int i2c_del_driver(struct i2c_driver *driver);

     5.   int i2c_attach_client(struct i2c_client *client); //增加client

     6.   int i2c_detach_client(struct i2c_client *client);


2)I2C傳輸,發(fā)送和接收

     1.   int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num);

     2.   int i2c_master_send(struct i2c_client *client,const char *buf ,int count);

     3.   int i2c_master_recv(struct i2c_client *client, char *buf ,int count);

i2c_transfer 函數(shù)用于進(jìn)行I2C適配器和I2C設(shè)備之間的一組消息交互。i2c_master_send函數(shù)和i2c_master_recv函數(shù)調(diào)用i2c_transfer函數(shù)分別完成一條寫消息和一條讀消息。而i2c_transfer函數(shù)實(shí)現(xiàn)中使用這句話adap->algo->master_xfer(adap,msgs,num);來(lái)調(diào)用i2c_algorithm中注冊(cè)的master_xfer函數(shù)。               

i2c_algorithm如下定義:

     1.   struct i2c_algorithm {

     2.       int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,

     3.                               int num);

     4.       int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,

     5.                               unsigned short flags, char read_write,

     6.                               u8 command, int size, union i2c_smbus_data *data);

     7.       u32 (*functionality) (struct i2c_adapter *);

     8.       }

根據(jù)定義主要要實(shí)現(xiàn)i2c_algorithm的master_xfer()函數(shù)和functionality()函數(shù)。







四、Algorithm中的傳輸函數(shù)master_xfer

圖6只是提供了一個(gè)大概的框架。在下面的代碼分析中,從Algorithm中的傳輸函數(shù)master_xfer來(lái)開(kāi)始分析整個(gè)結(jié)構(gòu)。以下的代碼分析是基于linux 3.0.4。分析的代碼基本位于: linux-3.0.4/drivers/i2c/位置。

博文以一款CPU的I2C模塊作為例子。

分析一個(gè)Linux驅(qū)動(dòng)代碼,一般都是從module_init()開(kāi)始,分析一個(gè)不帶操作系統(tǒng)的程序,一般從main函數(shù)開(kāi)始,此處我們分析I2C的總線驅(qū)動(dòng),從設(shè)備調(diào)用I2C總線驅(qū)動(dòng)的入口處開(kāi)始分析。在i2c-core.c中的i2c_transfer函數(shù)中,會(huì)有語(yǔ)句:ret = adap->algo->master_xfer(adap, msgs, num);來(lái)實(shí)現(xiàn)數(shù)據(jù)傳遞,實(shí)際此處就是I2C總線驅(qū)動(dòng)執(zhí)行的入口,相應(yīng)算法結(jié)構(gòu)體函數(shù)的賦值會(huì)在總線驅(qū)動(dòng)的探測(cè)函數(shù)中執(zhí)行,后面會(huì)講述。

算法結(jié)構(gòu)體賦值如下:

1.  static struct i2c_algorithm i2c_gsc_algo = {

2.      .master_xfer = i2c_gsc_xfer,

3.      .functionality = i2c_gsc_func,

4.  };

i2c_gsc_func()函數(shù)實(shí)現(xiàn)的就是總線驅(qū)動(dòng)支持的操作,程序如下:

1.  static u32 i2c_gsc_func(struct i2c_adapter *adap)

2.  {

3.   

4.      return I2C_FUNC_I2C |

5.          I2C_FUNC_10BIT_ADDR |

6.          I2C_FUNC_SMBUS_BYTE |

7.          I2C_FUNC_SMBUS_BYTE_DATA |

8.          I2C_FUNC_SMBUS_WORD_DATA |

9.          I2C_FUNC_SMBUS_I2C_BLOCK;

10.                                      }

i2c_gsc_xfer()函數(shù)實(shí)現(xiàn)開(kāi)始傳輸I2C數(shù)據(jù),程序如下:

1.  static int i2c_gsc_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)

2.  {

3.      struct gsc_i2c_dev *dev = i2c_get_adapdata(adap); //獲取總線設(shè)備結(jié)構(gòu)體,設(shè)置在probe函數(shù)中

4.      int ret;

5.      dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);

6.      //開(kāi)始初始化變量,準(zhǔn)備開(kāi)始傳輸

7.      mutex_lock(&dev->lock);

8.      INIT_COMPLETION(dev->cmd_complete);

9.      dev->msgs = msgs;

10.            dev->msgs_num = num;

11.            dev->cmd_err = 0;

12.            dev->msg_write_idx = 0; //此變量用來(lái)標(biāo)識(shí)傳輸?shù)降趲讉€(gè)dev->msgs,dev->msgs_num標(biāo)識(shí)總共有幾個(gè)msgs

13.            dev->msg_read_idx = 0;

14.            dev->msg_err = 0;

15.            dev->status = STATUS_IDLE;

16.            dev->abort_source = 0;

17.            ret = i2c_gsc_wait_bus_not_busy(dev); //查詢總線是否空閑,只有空閑才開(kāi)始傳輸 

18.            if (ret < 0)

19.                goto done;

20.            /* start the transfers */

21.            i2c_gsc_xfer_init(dev); //設(shè)置傳輸模式,開(kāi)啟中斷 

22.            /* wait for tx to complete */

23.            ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); //等待傳輸完成,中斷中會(huì)設(shè)置

24.            if (ret == 0) {

25.                dev_err(dev->dev, "controller timed out\n");

26.                i2c_gsc_init(dev);

27.                ret = -ETIMEDOUT;

28.                goto done;

29.            } else if (ret < 0)

30.                goto done;

31.            if (dev->msg_err) {

32.                ret = dev->msg_err;

33.                goto done;

34.            }

35.            /* no error */

36.            if (likely(!dev->cmd_err)) {

37.                /* Disable the adapter */

38.                writel(0, dev->base + GSC_IC_ENABLE);

39.                ret = num;

40.                goto done;

41.            }

42.            /* We have an error */

43.            if (dev->cmd_err == GSC_IC_ERR_TX_ABRT) {

44.                ret = i2c_gsc_handle_tx_abort(dev);

45.                goto done;

46.            }

47.            ret = -EIO;

48.        done:

49.            mutex_unlock(&dev->lock);

50.            return ret;

51.        }


從以上函數(shù)看出,當(dāng)執(zhí)行完此函數(shù)后,中斷打開(kāi),實(shí)際的傳輸在中斷中完成。

中斷號(hào)和申請(qǐng)中斷函數(shù)在總線驅(qū)動(dòng)的probe函數(shù)中完成,最后會(huì)講述。接下來(lái)就看下中斷函數(shù)i2c_gsc_isr:

1.  static irqreturn_t i2c_gsc_isr(int this_irq, void *dev_id)

2.  {

3.   

4.      struct gsc_i2c_dev *dev = dev_id;

5.      u32 stat;

6.      stat = i2c_gsc_read_clear_intrbits(dev); //清除中斷標(biāo)志位 

7.      dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat);

8.      if (stat & GSC_IC_INTR_TX_ABRT) {

9.          dev->cmd_err |= GSC_IC_ERR_TX_ABRT;

10.            dev->status = STATUS_IDLE;

11.            /*

12.     

13.             * Anytime TX_ABRT is set, the contents of the tx/rx

14.     

15.             * buffers are flushed. Make sure to skip them.

16.     

17.             */

18.            writel(0, dev->base + GSC_IC_INTR_MASK); //如果是傳輸終止則清除所有中斷 

19.            goto tx_aborted;

20.        }

21.        if (stat & GSC_IC_INTR_RX_FULL)

22.            i2c_gsc_read(dev); //接收f(shuō)ifo滿中斷,讀取數(shù)據(jù)

23.        if (stat & GSC_IC_INTR_TX_EMPTY)

24.            i2c_gsc_xfer_msg(dev); //發(fā)送fifo空中斷,發(fā)送數(shù)據(jù) 

25.        /*

26.         * No need to modify or disable the interrupt mask here.

27.         * i2c_gsc_xfer_msg() will take care of it according to

28.         * the current transmit status.

29.         */

30.    tx_aborted:

31.        if ((stat & (GSC_IC_INTR_TX_ABRT | GSC_IC_INTR_STOP_DET)) || dev->msg_err)

32.            complete(&dev->cmd_complete); //發(fā)送錯(cuò)誤或者發(fā)送終止,完成事件,對(duì)應(yīng)上面的wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);

33.        return IRQ_HANDLED;

34.    }


接下來(lái)看下:接收f(shuō)ifo滿中斷,讀取數(shù)據(jù)函數(shù):i2c_gsc_read()

1.     static void i2c_gsc_read(struct gsc_i2c_dev *dev)

2.     {

3.         struct i2c_msg *msgs = dev->msgs;

4.         int rx_valid;

5.         for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {

6.             u32 len;

7.             u8 *buf;

8.             if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))

9.                 continue;

10.            if (!(dev->status & STATUS_READ_IN_PROGRESS)) {

11.                //第一次開(kāi)始讀,設(shè)置長(zhǎng)度和存儲(chǔ)數(shù)組地址

12.                len = msgs[dev->msg_read_idx].len;

13.                buf = msgs[dev->msg_read_idx].buf;

14.            } else {

15.                /* 注意此處,如果是第一次開(kāi)始讀,讀的長(zhǎng)度和存儲(chǔ)數(shù)組都放在結(jié)構(gòu)體dev->msgs中,如果不是

16.                第一次讀,長(zhǎng)度和存儲(chǔ)數(shù)組放在dev->rx_buf_len和dev->rx_buf中,在本函數(shù)最后會(huì)判斷一次是否能夠

17.                讀完全,如果不完全,則更新dev->rx_buf_len和dev->rx_buf。*/

18.                len = dev->rx_buf_len;

19.                buf = dev->rx_buf;

20.            }

21.            rx_valid = readl(dev->base + GSC_IC_RXFLR); //讀取接收f(shuō)ifo里數(shù)據(jù)長(zhǎng)度 

22.            for (; len > 0 && rx_valid > 0; len--, rx_valid--)

23.                *buf++ = readl(dev->base + GSC_IC_DATA_CMD); //讀取數(shù)據(jù)

24.            if (len > 0) {

25.                //如果沒(méi)有讀取完成,設(shè)置狀態(tài)位,更新變量,和上面紅色的呼應(yīng)

26.                dev->status |= STATUS _READ_IN_PROGRESS;

27.                dev->rx_buf_len = len;

28.                dev->rx_buf = buf;

29.                return;

30.            } else

31.                dev->status &= ~STATUS_READ_IN_PROGRESS; //一次讀取完成

32.        }

33.    }


發(fā)送fifo空中斷,發(fā)送數(shù)據(jù)函數(shù)i2c_gsc_xfer_msg:

1.  static void i2c_gsc_xfer_msg(struct gsc_i2c_dev *dev)

2.  {

3.      struct i2c_msg *msgs = dev->msgs;

4.      u32 intr_mask;

5.      int tx_limit, rx_limit;

6.      u32 addr = msgs[dev->msg_write_idx].addr;

7.      u32 buf_len = dev->tx_buf_len;

8.      u8 *buf = dev->tx_buf;

9.      intr_mask = GSC_IC_INTR_DEFAULT_MASK; //設(shè)置默認(rèn)屏蔽位

10.          //使用dev->msg_write_idx標(biāo)識(shí)傳輸?shù)趲讉€(gè)msgs

11.          for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {

12.              /*

13.               * if target address has changed, we need to

14.               * reprogram the target address in the i2c

15.               * adapter when we are done with this transfer

16.               */

17.              //兩次傳輸?shù)刂凡灰粯?,退?/span>

18.              if (msgs[dev->msg_write_idx].addr != addr) {

19.                  dev_err(dev->dev,

20.                      "%s: invalid target address\n", __func__);

21.                  dev->msg_err = -EINVAL;

22.                  break;

23.              }

24.              //傳輸長(zhǎng)度為0,退出

25.              if (msgs[dev->msg_write_idx].len == 0) {

26.                  dev_err(dev->dev,

27.                      "%s: invalid message length\n", __func__);

28.                  dev->msg_err = -EINVAL;

29.                  break;

30.              }

31.              //如果是第一次傳輸,設(shè)置傳輸長(zhǎng)度和數(shù)組地址

32.              if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {

33.                  /* new i2c_msg */

34.                  buf = msgs[dev->msg_write_idx].buf;

35.                  buf_len = msgs[dev->msg_write_idx].len;

36.              }

37.              tx_limit = dev->tx_fifo_depth - readl(dev->base + GSC_IC_TXFLR); //計(jì)算可以往寄存器里寫幾個(gè)數(shù)據(jù) 

38.              rx_limit = dev->rx_fifo_depth - readl(dev->base + GSC_IC_RXFLR); //計(jì)算可以從寄存器里讀幾個(gè)數(shù)據(jù)

39.              while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {

40.                  u32 cmd = 0;

41.                  if((dev->msg_write_idx == dev->msgs_num-1) && buf_len == 1)

42.                      cmd |= 0x200; //最后一次傳輸,設(shè)置寄存器發(fā)送stop信號(hào)

43.                  if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {

44.                      writel(cmd|0x100, dev->base + GSC_IC_DATA_CMD); //寫命令,此處為讀

45.                      rx_limit--;

46.                  } else

47.                      writel(cmd|*buf++, dev->base + GSC_IC_DATA_CMD); //寫數(shù)據(jù)

48.                  tx_limit--; buf_len--;

49.              }

50.              //更新變量

51.              dev->tx_buf = buf;

52.              dev->tx_buf_len = buf_len;

53.              if (buf_len > 0) {

54.                  /* more bytes to be written */

55.                  dev->status |= STATUS_WRITE_IN_PROGRESS;

56.                  break;

57.              } else

58.                  dev->status &= ~STATUS_WRITE_IN_PROGRESS; //讀寫完成 

59.          }

60.          /*

61.           * If i2c_msg index search is completed, we don't need TX_EMPTY

62.           * interrupt any more.

63.           */

64.          if (dev->msg_write_idx == dev->msgs_num)

65.              intr_mask &= ~GSC_IC_INTR_TX_EMPTY; //如果寫完成,屏蔽發(fā)送中斷

66.          if (dev->msg_err)

67.              intr_mask = 0; //如果出現(xiàn)錯(cuò)誤,屏蔽所有中斷

68.          writel(intr_mask, dev->base + GSC_IC_INTR_MASK); //寫屏蔽寄存器

69.      }

到這里就講述完成了I2C數(shù)據(jù)傳輸中總線驅(qū)動(dòng)部分,接下來(lái)講述總線驅(qū)動(dòng)中的注冊(cè)和探測(cè)函數(shù)。



五、總線驅(qū)動(dòng)注冊(cè)和探測(cè)函數(shù)

和其他總線驅(qū)動(dòng)類似,I2C總線驅(qū)動(dòng)注冊(cè)成平臺(tái)設(shè)備,所以首先需要定義平臺(tái)設(shè)備,包括寄存器的起始地址和大小,中斷信息等。
接下來(lái)就是總線驅(qū)動(dòng)模塊的注冊(cè)和移除了,如下:

1.  static int __init gsc_i2c_init_driver(void)

2.  {

3.      return platform_driver_probe(&gsc_i2c_driver, gsc_i2c_probe);

4.  }

5.  static void __exit gsc_i2c_exit_driver(void)

6.  {

7.      platform_driver_unregister(&gsc_i2c_driver);

8.  }

9.  module_init(gsc_i2c_init_driver);

10.    module_exit(gsc_i2c_exit_driver);


平臺(tái)設(shè)備驅(qū)動(dòng)的結(jié)構(gòu)體如下:

1.  static struct platform_driver gsc_i2c_driver = {

2.      .remove = __devexit_p(gsc_i2c_remove),

3.      .driver = {

4.          .name = "XXXX-i2c",

5.          .owner = THIS_MODULE,

6.      },

7.  };


接下來(lái)就看下I2C總線驅(qū)動(dòng)的探測(cè)函數(shù)gsc_i2c_probe:

1.  static int __devinit gsc_i2c_probe(struct platform_device *pdev)

2.  {

3.      struct gsc_i2c_dev *dev;

4.      struct i2c_adapter *adap;

5.      struct resource *mem, *ioarea;

6.      int irq, r;

7.      //申請(qǐng)?jiān)O(shè)備資源

8.      /* NOTE: driver uses the static register mapping */

9.      mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

10.      if (!mem) {

11.          dev_err(&pdev->dev, "no mem resource?\n");

12.          return -EINVAL;

13.      }

14.      irq = platform_get_irq(pdev, 0);

15.      if (irq < 0) {

16.          dev_err(&pdev->dev, "no irq resource?\n");

17.          return irq; /* -ENXIO */

18.      }

19.      ioarea = request_mem_region(mem->start, resource_size(mem),

20.              pdev->name);

21.      if (!ioarea) {

22.          dev_err(&pdev->dev, "I2C region already claimed\n");

23.          return -EBUSY;

24.      }

25.      //申請(qǐng)總線結(jié)構(gòu)體變量

26.      dev = kzalloc(sizeof(struct gsc_i2c_dev), GFP_KERNEL);

27.      if (!dev) {

28.          r = -ENOMEM;

29.          goto err_release_region;

30.      }

31.      //初始化變量

32.      init_completion(&dev->cmd_complete);

33.      mutex_init(&dev->lock);

34.      dev->dev = get_device(&pdev->dev);

35.      dev->irq = irq;

36.      platform_set_drvdata(pdev, dev);

37.      dev->clk = clk_get(&pdev->dev, "i2c");

38.      if (IS_ERR(dev->clk)) {

39.          r = -ENODEV;

40.          goto err_free_mem;

41.      }

42.      clk_enable(dev->clk);

43.      dev->base = ioremap(mem->start, resource_size(mem));

44.      if (dev->base == NULL) {

45.          dev_err(&pdev->dev, "failure mapping io resources\n");

46.          r = -EBUSY;

47.          goto err_unuse_clocks;

48.      }

49.      //設(shè)置發(fā)送和接收f(shuō)ifo深度

50.      dev->tx_fifo_depth = 8;

51.      dev->rx_fifo_depth = 8;

52.      i2c_gsc_init(dev); //初始化I2C總線時(shí)鐘

53.      writel(0, dev->base + GSC_IC_INTR_MASK); /* disable IRQ */

54.      r = request_irq(dev->irq, i2c_gsc_isr, IRQF_DISABLED, pdev->name, dev); //申請(qǐng)中斷函數(shù),上面已經(jīng)講述

55.      if (r) {

56.          dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);

57.          goto err_iounmap;

58.      }

59.      //設(shè)置I2C的adap

60.      adap = &dev->adapter;

61.      i2c_set_adapdata(adap, dev);

62.      adap->owner = THIS_MODULE;

63.      adap->class = I2C_CLASS_HWMON;

64.      strlcpy(adap->name, "BLX GSC3280 I2C adapter",

65.              sizeof(adap->name));

66.      adap->algo = &i2c_gsc_algo; //設(shè)置adap的算法,包括傳輸函數(shù)和支持的操作函數(shù),本文開(kāi)始已經(jīng)講述

67.      adap->dev.parent = &pdev->dev;

68.      adap->nr = pdev->id;

69.      r = i2c_add_numbered_adapter(adap); //增加適配器計(jì)數(shù),后面講述

70.      if (r) {

71.          dev_err(&pdev->dev, "failure adding adapter\n");

72.          goto err_free_irq;

73.      }

74.      return 0;

75.      //中途退出分支

76.  err_free_irq:

77.      free_irq(dev->irq, dev);

78.  err_iounmap:

79.      iounmap(dev->base);

80.  err_unuse_clocks:

81.      clk_disable(dev->clk);

82.      clk_put(dev->clk);

83.      dev->clk = NULL;

84.  err_free_mem:

85.      platform_set_drvdata(pdev, NULL);

86.      put_device(&pdev->dev);

87.      kfree(dev);

88.  err_release_region:

89.      release_mem_region(mem->start, resource_size(mem));

90.      return r;

91.  }

在kernel中提供了兩個(gè)adapter注冊(cè)接口,分別為i2c_add_adapter()和i2c_add_numbered_adapter()。由于在系統(tǒng)中可能存在多個(gè)adapter,因此將每一條I2C總線對(duì)應(yīng)一個(gè)編號(hào),下文中稱為I2C總線號(hào)。這個(gè)總線號(hào)與PCI中的總線號(hào)不同。它和硬件無(wú)關(guān),只是軟件上便于區(qū)分而已。對(duì)于實(shí)際的設(shè)備,一條I2C總線就意味著CPU的一個(gè)I2C控制器,也對(duì)應(yīng)著一個(gè)adapter結(jié)構(gòu)體。

對(duì)于i2c_add_adapter()而言,它使用的是動(dòng)態(tài)總線號(hào),即由系統(tǒng)給其分配一個(gè)總線號(hào),而i2c_add_numbered_adapter()則是自己指定總線號(hào),如果這個(gè)總線號(hào)非法或者是被占用,就會(huì)注冊(cè)失敗。

1.  int i2c_add_adapter(struct i2c_adapter *adapter)

2.  {

3.      int id, res = 0;

4.  retry:

5.      if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)

6.          return -ENOMEM;

7.      mutex_lock(&core_lock);

8.      /* "above" here means "above or equal to", sigh */

9.      res = idr_get_new_above(&i2c_adapter_idr, adapter,

10.                      __i2c_first_dynamic_bus_num, &id);

11.          mutex_unlock(&core_lock);

12.          if (res < 0) {

13.              if (res == -EAGAIN)

14.                  goto retry;

15.              return res;

16.       

17.          }

18.          adapter->nr = id;

19.          return i2c_register_adapter(adapter);

20.      }


在這里涉及到一個(gè)idr結(jié)構(gòu)。idr結(jié)構(gòu)本來(lái)是為了配合page cache中的radix tree而設(shè)計(jì)的.在這里我們只需要知道,它是一種高效的搜索樹,且這個(gè)樹預(yù)先存放了一些內(nèi)存。避免在內(nèi)存不夠的時(shí)候出現(xiàn)問(wèn)題。所以,在往idr中插入結(jié)構(gòu)的時(shí)候,首先要調(diào)用idr_pre_get()為它預(yù)留足夠的空閑內(nèi)存,然后再調(diào)用idr_get_new_above()將結(jié)構(gòu)插入idr中,該函數(shù)以參數(shù)的形式返回一個(gè)id。以后憑這個(gè)id就可以在idr中找到相對(duì)應(yīng)的結(jié)構(gòu)了。

注意一下idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id)參數(shù)的含義,它是將adapter結(jié)構(gòu)插入到i2c_adapter_idr中,存放位置的id必須要大于或者等于__i2c_first_dynamic_bus_num,然后將對(duì)應(yīng)的id號(hào)存放在adapter->nr中。調(diào)用i2c_register_adapter(adapter)對(duì)這個(gè)adapter進(jìn)一步注冊(cè)。

1.   int i2c_add_numbered_adapter(struct i2c_adapter *adap)

2.   {

3.       int id;

4.       int status;

5.       if (adap->nr & ~MAX_ID_MASK)

6.           return -EINVAL;

7.   retry:

8.       if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)

9.           return -ENOMEM;

10.      mutex_lock(&core_lock);

11.      /* "above" here means "above or equal to", sigh;

12.       * we need the "equal to" result to force the result

13.       */

14.      status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);

15.      if (status == 0 && id != adap->nr) {

16.          status = -EBUSY;

17.          idr_remove(&i2c_adapter_idr, id);

18.      }

19.      mutex_unlock(&core_lock);

20.      if (status == -EAGAIN)

21.          goto retry;

22.      if (status == 0)

23.          status = i2c_register_adapter(adap);

24.      return status;

25.  }

對(duì)比一下就知道差別了,在這里它已經(jīng)指定好了adapter->nr了。如果分配的id不和指定的相等,便返回錯(cuò)誤。本文使用的注冊(cè)函數(shù)即為i2c_add_numbered_adapter。

i2c_register_adapter()代碼如下:

1.     static int i2c_register_adapter(struct i2c_adapter *adap)

2.     {

3.         int res = 0, dummy;

4.         mutex_init(&adap->bus_lock);

5.         mutex_init(&adap->clist_lock);

6.         INIT_LIST_HEAD(&adap->clients);

7.         mutex_lock(&core_lock);

8.         /* Add the adapter to the driver core.

9.         * If the parent pointer is not set up,

10.        * we add this adapter to the host bus.

11.        */

12.        if (adap->dev.parent == NULL) {

13.            adap->dev.parent = &platform_bus;

14.            pr_debug("I2C adapter driver [%s] forgot to specify "

15.                "physical device/n", adap->name);

16.        }

17.        sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);

18.        adap->dev.release = &i2c_adapter_dev_release;

19.        adap->dev.class = &i2c_adapter_class;

20.        res = device_register(&adap->dev);

21.        if (res)

22.            goto out_list;

23.        dev_dbg(&adap->dev, "adapter [%s] registered/n", adap->name);

24.        /* create pre-declared device nodes for new-style drivers */

25.        if (adap->nr < __i2c_first_dynamic_bus_num)

26.            i2c_scan_static_board_info(adap); //板級(jí)設(shè)備靜態(tài)掃描,第二部分會(huì)講述

27.        /* let legacy drivers scan this bus for matching devices */

28.        dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,

29.                    i2c_do_add_adapter);

30.    out_unlock:

31.        mutex_unlock(&core_lock);

32.        return res;

33.    out_list:

34.        idr_remove(&i2c_adapter_idr, adap->nr);

35.        goto out_unlock;

36.    }


首先對(duì)adapter和adapter中內(nèi)嵌的struct device結(jié)構(gòu)進(jìn)行必須的初始化,之后注冊(cè)adapter內(nèi)嵌的struct device。在這里注意一下adapter->dev的初始化,它的類別為i2c_adapter_class,如果沒(méi)有父結(jié)點(diǎn),則將其父結(jié)點(diǎn)設(shè)為platform_bus.adapter->dev的名字,為i2c + 總線號(hào)。




原文請(qǐng)參見(jiàn): http://blog.chinaunix.net/uid-25445243-id-3609731.html