一、I2C總線原理 | ||||
I2C是一種常用的串行總線,由串行數(shù)據(jù)線SDA 和串線時鐘線SCL組成。I2C是一種多主機控制總線,它和USB總線不同,USB是基于master-slave機制,任何設備的通信必須由主機發(fā)起才可以,而 I2C 是基于multi master機制,一條總線上可允許多個master。 系統(tǒng)的I2C模塊分為I2C總線控制器和I2C設備。I2C 總線控制器是CPU提供的控制I2C總線接口,它控制I2C總線的協(xié)議、仲裁、時序。I2C設備是指通過I2C總線與CPU相連的設備,如EEPROM。使用I2C通信時必須指定主從設備。一般來說,I2C總線控制器被配置成主設備,與總線相連的I2C設備如AT24C02作為從設備。 | ||||
1.1、IIC讀寫原理 | ||||
IIC總線的開始/停止信號如圖1所示。開始信號為:時鐘信號線SCL為高電平,數(shù)據(jù)線SDA從高變低。停止信號為:時鐘信號線SCL為高電平,數(shù)據(jù)線SDA從低變高。 | ||||
圖1 IIC Start-Stop Signal | ||||
1.2、IIC總線Byte Write | ||||
IIC總線寫數(shù)據(jù)分幾種格式,如字節(jié)寫和頁寫。 字節(jié)寫傳送格式如圖2所示。開始信號之后,總線開始發(fā)數(shù)據(jù),第一個Byte是IIC的設備地址,第二個Byte是設備內的地址(如EEPROM中具體的某個物理地址),然后就是要傳送的真正的數(shù)據(jù)DATA。 NOTE:IIC 總線在傳送每個Byte后,都會從IIC總線上的接收設備得到一個ACK信號來確認接收到了數(shù)據(jù)。其中,第一個Byte的設備地址中,前7位是地址碼,第8位是方向位(“0”為發(fā)送,“1”為接收)。IIC的中斷信號有:ACK,Start,Stop。 | ||||
Write功能的實際實現(xiàn)原理如圖3所示: (1)設置GPIO的相關引腳為IIC輸出; (2)設置IIC(打開ACK,打開IIC中斷,設置CLK等); (3)設備地址賦給IICDS ,并設置IICSTAT,啟動IIC發(fā)送設備地址出去;從而找到相應的設備即IIC總線上的設備。 (4)第一個Byte的設備地址發(fā)送后,從EEPROM得到ACK信號,此信號觸發(fā)中斷; (5)在中斷處理函數(shù)中把第二個Byte(設備內地址)發(fā)送出去;發(fā)送之后,接收到ACK又觸發(fā)中斷; (6)中斷處理函數(shù)把第三個Byte(真正的數(shù)據(jù))發(fā)送到設備中。 (7)發(fā)送之后同樣接收到ACK并觸發(fā)中斷,中斷處理函數(shù)判斷,發(fā)現(xiàn)數(shù)據(jù)傳送完畢。 (8)IIC Stop信號,關IIC中斷,置位各寄存器。 | ||||
圖3 IIC Write Operation | ||||
NOTE:對于EEPROM,IICDS寄存器發(fā)送的數(shù)據(jù)會先放在Ring buffer中,當其收到stop信號時,開始實際寫入EEPROM中。在實際寫的過程中,EEPROM不響應從CPU來的信號,直到寫完才會響應,因而有一段延遲代碼。在page write時,注意一定要有延時! NOTE:數(shù)據(jù)先寫到EEPROM的ring buffer中,收到Stop信號時,開始實際地把數(shù)據(jù)寫入EEPROM,這時不響應任何輸入。即這時Write函數(shù)中后面的延時中,向其發(fā)slvaddr時,不會得到ACK,直到數(shù)據(jù)寫完時,才會收到ACK。 | ||||
1.3、IIC總線Random Read | ||||
IIC總線讀數(shù)據(jù)為Current Address Read,Random Read,Sequential Read IIC 總線Random Read傳送格式如圖4所示。開始信號后,CPU開始寫第一個Byte(IIC的設備地址),第二個Byte是設備內的地址(此地址保存在設備中)。然后開始讀過程:發(fā)送設備地址找到IIC設備,然后就開始讀數(shù)據(jù)。類似寫過程,CPU讀一個byte的實際數(shù)據(jù)后,CPU向IIC的EEPROM 發(fā)ACK,ACK觸發(fā)中斷。讀數(shù)據(jù)也在中斷程序中進行。 | ||||
圖4 IIC Random Read Operation | ||||
二、I2C架構概述 | ||||
在linux中,I2C驅動架構如下所示: | ||||
圖5 I2C驅動架構1 | ||||
Linux中I2C體系結構如下圖所示(圖片來源于網(wǎng)絡)。圖中用分割線分成了三個層次:用戶空間(也就是應用程序),內核(也就是驅動部分)和硬件(也就是實際物理設備)。我們現(xiàn)在就是要研究中間那一層。 | ||||
2.1、I2C驅動概述 | ||||
Linux的I2C驅動結構可分為3個部分: b、I2C總線驅動 c、I2C設備驅動 | ||||
圖6 I2C驅動架構2 | ||||
三、I2C代碼在內核中的結構 | ||||
3.1 I2C驅動調用關系 | ||||
內核中對于I2C定義了4種結構: 1)i2c_adapter—I2C總線適配器。即為CPU中的I2C總線控制器。 2)i2c_algorithm—I2C總線通信傳輸算法,管理I2C總線控制器,實現(xiàn)I2C總線上數(shù)據(jù)的發(fā)送和接收等操作。 3)i2c_client—掛載在I2C總線上的I2C設備的驅動程序。 4)i2c_driver—用于管理I2C的驅動程序,它對應I2C的設備節(jié)點。 這4種結構的定義見include/linux/i2c.h文件。 對于i2c_driver和i2c_client,i2c_driver對應一套驅動方法,是純粹的用于輔助作用的數(shù)據(jù)結構,它不對應于任何的物理實體。 i2c_client對應于真實的物理設備,每個I2C設備都需要一個i2c_client來描述。i2c_client 一般被包含在i2c字符設備的私有信息結構體中。i2c_driver 與i2c_client發(fā)生關聯(lián)的時刻在i2c_driver的attach_adapter()函數(shù)被運行時。attach_adapter()會探測物理設備,當確定一個client存在時,把該client使用的i2c_client數(shù)據(jù)結構的adapter指針指向對應的i2c_adapter,driver指針指向該i2c_driver,并會調用i2c_adapter的client_register()函數(shù)。相反的過程發(fā)生在i2c_driver 的detach_client()函數(shù)被調用的時候。 對于i2c_adpater 與i2c_client,與I2C硬件體系中適配器和設備的關系一致,即i2c_client依附于i2c_adpater。由于一個適配器上可以連接多個I2C設備,所以一個i2c_adpater也可以被多個i2c_client依附,i2c_adpater中包括依附于它的i2c_client的鏈表。 i2c.h文件中除定義上述4個重要結構之外,還定義了一個非常重要的結構體: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. }; | ||||
3.2 內核中的I2C驅動 | ||||
Linux內核源碼的drivers目錄下有個i2c目錄,其中包含如下文件和文件夾: a、i2c-core.c 這個文件實現(xiàn)了I2C核心的功能以及/proc/bus/i2c*接口。 b、i2c-dev.c 實現(xiàn)了I2C適配器設備文件的功能,每一個I2C適配器都被分配一個設備。通過適配器訪問設備時的主設備號都為89,次設備號為0~255。應用程序通過“i2c-%d” (i2c-0, i2c-1, ..., i2c-10, ...)文件名并使用文件操作接口open()、write()、read()、ioctl()和close()等來訪問這個設備。 i2c-dev.c并沒有針對特定的設備而設計,只是提供了通用的read()、write()和ioctl()等接口,應用層可以借用這些接口訪問掛接在適配器上I2C設備的存儲空間或寄存器,并控制I2C設備的工作方式。 c、chips文件夾 此目錄中包含了一些特定的I2C設備驅動,如RTC實時鐘芯片驅動和I2C接口的EEPROM驅動等。 d、busses文件夾 此目錄中包含了一些I2C總線的驅動,如S3C2410的I2C控制器驅動為i2c-s3c2410.c。 e、algos文件夾 實現(xiàn)了一些I2C總線適配器的algorithm。 i2c-core.c文件不需要修改,其主要實現(xiàn)的函數(shù)有: 1)adapter和client相關操作 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 *); //增加驅動 (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ù)用于進行I2C適配器和I2C設備之間的一組消息交互。i2c_master_send函數(shù)和i2c_master_recv函數(shù)調用i2c_transfer函數(shù)分別完成一條寫消息和一條讀消息。而i2c_transfer函數(shù)實現(xiàn)中使用這句話adap->algo->master_xfer(adap,msgs,num);來調用i2c_algorithm中注冊的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ù)定義主要要實現(xiàn)i2c_algorithm的master_xfer()函數(shù)和functionality()函數(shù)。 | ||||
四、Algorithm中的傳輸函數(shù)master_xfer | ||||
圖6只是提供了一個大概的框架。在下面的代碼分析中,從Algorithm中的傳輸函數(shù)master_xfer來開始分析整個結構。以下的代碼分析是基于linux 3.0.4。分析的代碼基本位于: linux-3.0.4/drivers/i2c/位置。 博文以一款CPU的I2C模塊作為例子。 分析一個Linux驅動代碼,一般都是從module_init()開始,分析一個不帶操作系統(tǒng)的程序,一般從main函數(shù)開始,此處我們分析I2C的總線驅動,從設備調用I2C總線驅動的入口處開始分析。在i2c-core.c中的i2c_transfer函數(shù)中,會有語句:ret = adap->algo->master_xfer(adap, msgs, num);來實現(xiàn)數(shù)據(jù)傳遞,實際此處就是I2C總線驅動執(zhí)行的入口,相應算法結構體函數(shù)的賦值會在總線驅動的探測函數(shù)中執(zhí)行,后面會講述。 算法結構體賦值如下: 1. static struct i2c_algorithm i2c_gsc_algo = { 2. .master_xfer = i2c_gsc_xfer, 3. .functionality = i2c_gsc_func, 4. }; i2c_gsc_func()函數(shù)實現(xiàn)的就是總線驅動支持的操作,程序如下: 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. } 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); //獲取總線設備結構體,設置在probe函數(shù)中 4. int ret; 5. dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); 6. //開始初始化變量,準備開始傳輸 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; //此變量用來標識傳輸?shù)降趲讉€dev->msgs,dev->msgs_num標識總共有幾個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); //查詢總線是否空閑,只有空閑才開始傳輸 18. if (ret < 0) 19. goto done; 20. /* start the transfers */ 21. i2c_gsc_xfer_init(dev); //設置傳輸模式,開啟中斷 22. /* wait for tx to complete */ 23. ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); //等待傳輸完成,中斷中會設置 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ù)看出,當執(zhí)行完此函數(shù)后,中斷打開,實際的傳輸在中斷中完成。 中斷號和申請中斷函數(shù)在總線驅動的probe函數(shù)中完成,最后會講述。接下來就看下中斷函數(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); //清除中斷標志位 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); //接收fifo滿中斷,讀取數(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ā)送錯誤或者發(fā)送終止,完成事件,對應上面的wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); 33. return IRQ_HANDLED; 34. } 接下來看下:接收fifo滿中斷,讀取數(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. //第一次開始讀,設置長度和存儲數(shù)組地址 12. len = msgs[dev->msg_read_idx].len; 13. buf = msgs[dev->msg_read_idx].buf; 14. } else { 15. /* 注意此處,如果是第一次開始讀,讀的長度和存儲數(shù)組都放在結構體dev->msgs中,如果不是 16. 第一次讀,長度和存儲數(shù)組放在dev->rx_buf_len和dev->rx_buf中,在本函數(shù)最后會判斷一次是否能夠 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); //讀取接收fifo里數(shù)據(jù)長度 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. //如果沒有讀取完成,設置狀態(tài)位,更新變量,和上面紅色的呼應 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; //設置默認屏蔽位 10. //使用dev->msg_write_idx標識傳輸?shù)趲讉€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. //傳輸長度為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ù)組地址 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); //計算可以往寄存器里寫幾個數(shù)據(jù) 38. rx_limit = dev->rx_fifo_depth - readl(dev->base + GSC_IC_RXFLR); //計算可以從寄存器里讀幾個數(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; //最后一次傳輸,設置寄存器發(fā)送stop信號 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)錯誤,屏蔽所有中斷 68. writel(intr_mask, dev->base + GSC_IC_INTR_MASK); //寫屏蔽寄存器 69. } 到這里就講述完成了I2C數(shù)據(jù)傳輸中總線驅動部分,接下來講述總線驅動中的注冊和探測函數(shù)。 | ||||
五、總線驅動注冊和探測函數(shù) | ||||
和其他總線驅動類似,I2C總線驅動注冊成平臺設備,所以首先需要定義平臺設備,包括寄存器的起始地址和大小,中斷信息等。 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);
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. }; 接下來就看下I2C總線驅動的探測函數(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. //申請設備資源 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. //申請總線結構體變量 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. //設置發(fā)送和接收fifo深度 50. dev->tx_fifo_depth = 8; 51. dev->rx_fifo_depth = 8; 52. i2c_gsc_init(dev); //初始化I2C總線時鐘 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); //申請中斷函數(shù),上面已經(jīng)講述 55. if (r) { 56. dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); 57. goto err_iounmap; 58. } 59. //設置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; //設置adap的算法,包括傳輸函數(shù)和支持的操作函數(shù),本文開始已經(jīng)講述 67. adap->dev.parent = &pdev->dev; 68. adap->nr = pdev->id; 69. r = i2c_add_numbered_adapter(adap); //增加適配器計數(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中提供了兩個adapter注冊接口,分別為i2c_add_adapter()和i2c_add_numbered_adapter()。由于在系統(tǒng)中可能存在多個adapter,因此將每一條I2C總線對應一個編號,下文中稱為I2C總線號。這個總線號與PCI中的總線號不同。它和硬件無關,只是軟件上便于區(qū)分而已。對于實際的設備,一條I2C總線就意味著CPU的一個I2C控制器,也對應著一個adapter結構體。 對于i2c_add_adapter()而言,它使用的是動態(tài)總線號,即由系統(tǒng)給其分配一個總線號,而i2c_add_numbered_adapter()則是自己指定總線號,如果這個總線號非法或者是被占用,就會注冊失敗。 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. } 在這里涉及到一個idr結構。idr結構本來是為了配合page cache中的radix tree而設計的.在這里我們只需要知道,它是一種高效的搜索樹,且這個樹預先存放了一些內存。避免在內存不夠的時候出現(xiàn)問題。所以,在往idr中插入結構的時候,首先要調用idr_pre_get()為它預留足夠的空閑內存,然后再調用idr_get_new_above()將結構插入idr中,該函數(shù)以參數(shù)的形式返回一個id。以后憑這個id就可以在idr中找到相對應的結構了。 注意一下idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id)參數(shù)的含義,它是將adapter結構插入到i2c_adapter_idr中,存放位置的id必須要大于或者等于__i2c_first_dynamic_bus_num,然后將對應的id號存放在adapter->nr中。調用i2c_register_adapter(adapter)對這個adapter進一步注冊。 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. } 對比一下就知道差別了,在這里它已經(jīng)指定好了adapter->nr了。如果分配的id不和指定的相等,便返回錯誤。本文使用的注冊函數(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); //板級設備靜態(tài)掃描,第二部分會講述 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. }
| ||||
原文請參見: http://blog.chinaunix.net/uid-25445243-id-3609731.html | ||||