linux驅動--i2c驅動學習

轉至:http://blog.csdn.net/ghostyu/article/details/8094049

預備知識

在閱讀本文最好先熟悉一種i2c設備的驅動程序,並且瀏覽一下i2c-core.c以及芯片提供商的提供的i2c總線驅動(i2c-davinci.c)。標題黨請見諒!

其實i2c接口非常的簡單,即使用51單片的gpio來模擬i2c,編寫一個e2prom或者其他i2c接口的驅動程序,也不是什麼難事,幾百行代碼就能搞定。

但是Linux的i2c驅動體系結構卻有相當的複雜度,不管是叫linux i2c驅動還是單片機i2c驅動,其根本還是操作soc芯片內部的i2c模塊(也叫i2c adapter)(讀寫i2c相關的寄存器)來產生start、stop還有ack信號而已。

linux設備驅動到底複雜在什麼地方?

假設soc芯片dm368有兩個i2c adapter(368內部真正只有一個i2c模塊):i2c_adapter1,i2c_adapter1;然後外部有三個i2c接口的設備i2c_device1,i2c_device2,i2c_device3。

現在要求在裸機下寫出他們的驅動函數。那麼肯定要寫出6個不同的驅動函數:

  1. i2c_adapter1_ReadWrite_i2c_device1();  
  2. i2c_adapter1_ReadWrite_i2c_device2()  
  3. i2c_adapter1_ReadWrite_i2c_device3()  
  4. i2c_adapter2_ReadWrite_i2c_device1()  
  5. i2c_adapter2_ReadWrite_i2c_device2()  
  6. i2c_adapter2_ReadWrite_i2c_device3()  
i2c_adapter1_ReadWrite_i2c_device1();
i2c_adapter1_ReadWrite_i2c_device2()
i2c_adapter1_ReadWrite_i2c_device3()
i2c_adapter2_ReadWrite_i2c_device1()
i2c_adapter2_ReadWrite_i2c_device2()
i2c_adapter2_ReadWrite_i2c_device3()
設想一共有m個i2c adapter和n個外設i2c device,那麼將需要m*n個驅動。並且這m*n個驅動程序必要會有很大部分重複的代碼,而且不利於驅動程序的移植。

如果採用adapter和device分離的思想來寫這樣的驅動會是怎樣呢?


圖1

這樣分離之後,只需要m+n個驅動,而且Adapter和Device的幾乎沒有耦合性,增加一個Adapter或者device並不會影響其餘的驅動。

這就是分離思想帶來的好處。除此之外,linux雖然是C寫的,但是大量使用了面向對象的編程方法(可以理解爲分層的思想),

僅僅分離細想和分層思想的引入,就大大增加了linux設備驅動的複雜度。


linux驅動中 i2c驅動架構


圖2

上圖完整的描述了linux i2c驅動架構,雖然I2C硬件體系結構比較簡單,但是i2c體系結構在linux中的實現卻相當複雜。那麼我們如何編寫特定i2c接口器件(比如,ov2715,需要i2c來配置寄存器)的驅動程序?就是說上述架構中的那些部分需要我們完成,而哪些是linux內核已經完善的或者是芯片提供商(TI davinci平臺已經做好的)已經提供的?

架構層次分類

第一層:提供i2c adapter的硬件驅動,探測、初始化i2c adapter(如申請i2c的io地址和中斷號),驅動soc控制的i2c adapter在硬件上產生信號(start、stop、ack)以及處理i2c中斷。覆蓋圖中的硬件實現層

第二層:提供i2c adapter的algorithm,用具體適配器的xxx_xferf()函數來填充i2c_algorithm的master_xfer函數指針,並把賦值後的i2c_algorithm再賦值給i2c_adapter的algo指針。覆蓋圖中的訪問抽象層、i2c核心層

第三層:實現i2c設備驅動中的i2c_driver接口,用具體的i2c device設備的attach_adapter()、detach_adapter()方法賦值給i2c_driver的成員函數指針。實現設備device與總線(或者叫adapter)的掛接。覆蓋圖中的driver驅動層

第四層:實現i2c設備所對應的具體device的驅動,i2c_driver只是實現設備與總線的掛接,而掛接在總線上的設備則是千差萬別的,eeprom和ov2715顯然不是同一類的device,所以要實現具體設備device的write()、read()、ioctl()等方法,賦值給file_operations,然後註冊字符設備(多數是字符設備)。覆蓋圖中的driver驅動層

第一層和第二層又叫i2c總線驅動(bus),第三第四屬於i2c設備驅動(device driver)。在linux驅動架構中,幾乎不需要驅動開發人員再添加bus,因爲linux內核幾乎集成所有總線bus,如usb、pci、i2c等等。並且總線bus中的【與特定硬件相關的代碼】已由芯片提供商編寫完成,例如TI davinci平臺i2c總線bus與硬件相關的代碼在內核目錄/drivers/i2c/buses下的i2c-davinci.c源文件中;而三星的s3c-2440平臺i2c總線bus爲/drivers/i2c/buses/i2c-s3c2410.c

第三第四層又叫設備驅動層與特定device相干的就需要驅動工程師來實現了。

明確了方向後,再來具體分析。

具體分析

i2c_adapter與i2c_client的關係與i2c硬件體系中設配器與設備的關係一致,即i2c_client依附於i2c_adapter,由於一個適配器上可以連接多個i2c設備device,所以相應的,i2c_adapter也可以被多個i2c_client依附,在i2c_adapter中包含i2c_client的鏈表。同一類的i2c設備device對應一個驅動driver。driver與device的關係是一對多的關係。

現在,我們就來看一下這幾個重要的結構體,分別是i2c_driver i2c_client i2c_adapter,也可以先忽略他們,待會回過頭來看會更容易理解

1、i2c_driver

  1. struct i2c_driver {  
  2.     int id;  
  3.     unsigned int class;  
  4.   
  5.     int (*attach_adapter)(struct i2c_adapter *);  
  6.     int (*detach_adapter)(struct i2c_adapter *);  
  7.   
  8.     int (*detach_client)(struct i2c_client *);  
  9.   
  10.     int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);  
  11.     struct device_driver driver;  
  12.     struct list_head list;  
  13. };  
struct i2c_driver {
	int id;
	unsigned int class;

	int (*attach_adapter)(struct i2c_adapter *);
	int (*detach_adapter)(struct i2c_adapter *);

	int (*detach_client)(struct i2c_client *);

	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
	struct device_driver driver;
	struct list_head list;
};

2、i2c_client

  1. struct i2c_client {  
  2.     unsigned int flags;     /* div., see below      */  
  3.     unsigned short addr;        /* chip address - NOTE: 7bit    */  
  4.                     /* addresses are stored in the  */  
  5.                     /* _LOWER_ 7 bits       */  
  6.     struct i2c_adapter *adapter;    /* the adapter we sit on    */  
  7.     struct i2c_driver *driver;  /* and our access routines  */  
  8.     int usage_count;        /* How many accesses currently  */  
  9.                     /* to the client        */  
  10.     struct device dev;      /* the device structure     */  
  11.     struct list_head list;  
  12.     char name[I2C_NAME_SIZE];  
  13.     struct completion released;  
  14. };  
struct i2c_client {
	unsigned int flags;		/* div., see below		*/
	unsigned short addr;		/* chip address - NOTE: 7bit 	*/
					/* addresses are stored in the	*/
					/* _LOWER_ 7 bits		*/
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
	struct i2c_driver *driver;	/* and our access routines	*/
	int usage_count;		/* How many accesses currently  */
					/* to the client		*/
	struct device dev;		/* the device structure		*/
	struct list_head list;
	char name[I2C_NAME_SIZE];
	struct completion released;
};

3、i2c_adapter

  1. struct i2c_adapter {  
  2.     struct module *owner;  
  3.     unsigned int id;  
  4.     unsigned int class;  
  5.     struct i2c_algorithm *algo;/* the algorithm to access the bus   */  
  6.     void *algo_data;  
  7.   
  8.     /* --- administration stuff. */  
  9.     int (*client_register)(struct i2c_client *);  
  10.     int (*client_unregister)(struct i2c_client *);  
  11.   
  12.     /* data fields that are valid for all devices   */  
  13.     struct mutex bus_lock;  
  14.     struct mutex clist_lock;  
  15.   
  16.     int timeout;  
  17.     int retries;  
  18.     struct device dev;      /* the adapter device */  
  19.     struct class_device class_dev;  /* the class device */  
  20.   
  21.     int nr;  
  22.     struct list_head clients;  
  23.     struct list_head list;  
  24.     char name[I2C_NAME_SIZE];  
  25.     struct completion dev_released;  
  26.     struct completion class_dev_released;  
  27. };  
struct i2c_adapter {
	struct module *owner;
	unsigned int id;
	unsigned int class;
	struct i2c_algorithm *algo;/* the algorithm to access the bus	*/
	void *algo_data;

	/* --- administration stuff. */
	int (*client_register)(struct i2c_client *);
	int (*client_unregister)(struct i2c_client *);

	/* data fields that are valid for all devices	*/
	struct mutex bus_lock;
	struct mutex clist_lock;

	int timeout;
	int retries;
	struct device dev;		/* the adapter device */
	struct class_device class_dev;	/* the class device */

	int nr;
	struct list_head clients;
	struct list_head list;
	char name[I2C_NAME_SIZE];
	struct completion dev_released;
	struct completion class_dev_released;
};

4、i2c_algorithm

  1. struct i2c_algorithm {  
  2.     int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,   
  3.                        int num);  
  4.     int (*slave_send)(struct i2c_adapter *,char*,int);  
  5.     int (*slave_recv)(struct i2c_adapter *,char*,int);  
  6.     u32 (*functionality) (struct i2c_adapter *);  
  7. };  
struct i2c_algorithm {
	int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, 
	                   int num);
	int (*slave_send)(struct i2c_adapter *,char*,int);
	int (*slave_recv)(struct i2c_adapter *,char*,int);
	u32 (*functionality) (struct i2c_adapter *);
};

【i2c_adapter與i2c_algorithm】

i2c_adapter對應與物理上的一個適配器,而i2c_algorithm對應一套通信方法,一個i2c適配器需要i2c_algorithm中提供的(i2c_algorithm中的又是更下層與硬件相關的代碼提供)通信函數來控制適配器上產生特定的訪問週期。缺少i2c_algorithm的i2c_adapter什麼也做不了,因此i2c_adapter中包含其使用i2c_algorithm的指針。

i2c_algorithm中的關鍵函數master_xfer()用於產生i2c訪問週期需要的start stop ack信號,以i2c_msg(即i2c消息)爲單位發送和接收通信數據。i2c_msg也非常關鍵,調用驅動中的發送接收函數需要填充該結構體

  1. /* 
  2.  * I2C Message - used for pure i2c transaction, also from /dev interface 
  3.  */  
  4. struct i2c_msg {  
  5.     __u16 addr; /* slave address            */  
  6.     __u16 flags;          
  7.     __u16 len;      /* msg length               */  
  8.     __u8 *buf;      /* pointer to msg data          */  
  9. };  
/*
 * I2C Message - used for pure i2c transaction, also from /dev interface
 */
struct i2c_msg {
	__u16 addr;	/* slave address			*/
 	__u16 flags;		
 	__u16 len;		/* msg length				*/
 	__u8 *buf;		/* pointer to msg data			*/
};
【i2c_driver和i2c_client】

i2c_driver對應一套驅動方法,其主要函數是attach_adapter()和detach_client(),i2c_client對應真實的i2c物理設備device,每個i2c設備都需要一個i2c_client來描述,i2c_driver與i2c_client的關係是一對多。一個i2c_driver上可以支持多個同等類型的i2c_client.

【i2c_adapter和i2c_client】

i2c_adapter和i2c_client的關係與i2c硬件體系中適配器和設備的關係一致,即i2c_client依附於i2c_adapter,由於一個適配器上可以連接多個i2c設備,所以i2c_adapter中包含依附於它的i2c_client的鏈表。

從圖1圖2中都可以看出,linux內核對i2c架構抽象了一個叫核心層core的中間件,它分離了設備驅動device driver和硬件控制的實現細節(如操作i2c的寄存器),core層不但爲上面的設備驅動提供封裝後的內核註冊函數,而且還爲小面的硬件時間提供註冊接口(也就是i2c總線註冊接口),可以說core層起到了承上啓下的作用。

我們先看一下i2c-core爲外部提供的核心函數(選取部分),i2c-core對應的源文件爲i2c-core.c,位於內核目錄/driver/i2c/i2c-core.c

  1. EXPORT_SYMBOL(i2c_add_adapter);  
  2. EXPORT_SYMBOL(i2c_del_adapter);  
  3. EXPORT_SYMBOL(i2c_del_driver);  
  4. EXPORT_SYMBOL(i2c_attach_client);  
  5. EXPORT_SYMBOL(i2c_detach_client);  
  6.   
  7. EXPORT_SYMBOL(i2c_transfer);  
EXPORT_SYMBOL(i2c_add_adapter);
EXPORT_SYMBOL(i2c_del_adapter);
EXPORT_SYMBOL(i2c_del_driver);
EXPORT_SYMBOL(i2c_attach_client);
EXPORT_SYMBOL(i2c_detach_client);

EXPORT_SYMBOL(i2c_transfer);

如果看過i2c設備驅動程序的人一定對上面幾個函數比較熟悉。

i2c_transfer()函數,i2c_transfer()函數本身並不具備驅動適配器物理硬件完成消息交互的能力,它只是尋找到i2c_adapter對應的i2c_algorithm,並使用i2c_algorithm的master_xfer()函數真正的驅動硬件流程,代碼清單如下,不重要的已刪除。

  1. int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)  
  2. {  
  3.     int ret;  
  4.     if (adap->algo->master_xfer) {//如果master_xfer函數存在,則調用,否則返回錯誤  
  5.         ret = adap->algo->master_xfer(adap,msgs,num);//這個函數在硬件相關的代碼中給algorithm賦值  
  6.         return ret;  
  7.     } else {  
  8.         return -ENOSYS;  
  9.     }  
  10. }  
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
{
	int ret;
	if (adap->algo->master_xfer) {//如果master_xfer函數存在,則調用,否則返回錯誤
		ret = adap->algo->master_xfer(adap,msgs,num);//這個函數在硬件相關的代碼中給algorithm賦值
		return ret;
	} else {
		return -ENOSYS;
	}
}
當一個具體的client被偵測到並被關聯的時候,設備和sysfs文件將被註冊。相反的,在client被取消關聯的時候,sysfs文件和設備也被註銷,驅動開發人員需開發i2c設備驅動時,需要調用下列函數。程序清單如下
  1. int i2c_attach_client(struct i2c_client *client)  
  2. {  
  3.     ...  
  4.     device_register(&client->dev);  
  5.     device_create_file(&client->dev, &dev_attr_client_name);  
  6.     ...  
  7.     return 0;  
  8. }  
int i2c_attach_client(struct i2c_client *client)
{
	...
	device_register(&client->dev);
	device_create_file(&client->dev, &dev_attr_client_name);
	...
	return 0;
}
  1. int i2c_detach_client(struct i2c_client *client)  
  2. {  
  3.     ...  
  4.     device_remove_file(&client->dev, &dev_attr_client_name);  
  5.     device_unregister(&client->dev);  
  6.     ...  
  7.     return res;  
  8. }  
int i2c_detach_client(struct i2c_client *client)
{
	...
	device_remove_file(&client->dev, &dev_attr_client_name);
	device_unregister(&client->dev);
	...
	return res;
}
i2c_add_adapter()函數和i2c_del_adapter()在i2c-davinci.c中有調用,稍後分析
  1. /* ----- 
  2.  * i2c_add_adapter is called from within the algorithm layer, 
  3.  * when a new hw adapter registers. A new device is register to be 
  4.  * available for clients. 
  5.  */  
  6. int i2c_add_adapter(struct i2c_adapter *adap)  
  7. {  
  8.     ...  
  9.     device_register(&adap->dev);  
  10.     device_create_file(&adap->dev, &dev_attr_name);  
  11.     ...  
  12.     /* inform drivers of new adapters */  
  13.     list_for_each(item,&drivers) {  
  14.         driver = list_entry(item, struct i2c_driver, list);  
  15.         if (driver->attach_adapter)  
  16.             /* We ignore the return code; if it fails, too bad */  
  17.             driver->attach_adapter(adap);  
  18.     }  
  19.     ...  
  20. }  
/* -----
 * i2c_add_adapter is called from within the algorithm layer,
 * when a new hw adapter registers. A new device is register to be
 * available for clients.
 */
int i2c_add_adapter(struct i2c_adapter *adap)
{
	...
	device_register(&adap->dev);
	device_create_file(&adap->dev, &dev_attr_name);
	...
	/* inform drivers of new adapters */
	list_for_each(item,&drivers) {
		driver = list_entry(item, struct i2c_driver, list);
		if (driver->attach_adapter)
			/* We ignore the return code; if it fails, too bad */
			driver->attach_adapter(adap);
	}
	...
}
  1. int i2c_del_adapter(struct i2c_adapter *adap)  
  2. {  
  3.     ...  
  4.     list_for_each(item,&drivers) {  
  5.         driver = list_entry(item, struct i2c_driver, list);  
  6.         if (driver->detach_adapter)  
  7.             if ((res = driver->detach_adapter(adap))) {  
  8.             }  
  9.     }  
  10.     ...  
  11.     list_for_each_safe(item, _n, &adap->clients) {  
  12.         client = list_entry(item, struct i2c_client, list);  
  13.   
  14.         if ((res=client->driver->detach_client(client))) {  
  15.   
  16.         }  
  17.     }  
  18.     ...  
  19.     device_remove_file(&adap->dev, &dev_attr_name);  
  20.     device_unregister(&adap->dev);  
  21.   
  22. }  
int i2c_del_adapter(struct i2c_adapter *adap)
{
	...
	list_for_each(item,&drivers) {
		driver = list_entry(item, struct i2c_driver, list);
		if (driver->detach_adapter)
			if ((res = driver->detach_adapter(adap))) {
			}
	}
	...
	list_for_each_safe(item, _n, &adap->clients) {
		client = list_entry(item, struct i2c_client, list);

		if ((res=client->driver->detach_client(client))) {

		}
	}
	...
	device_remove_file(&adap->dev, &dev_attr_name);
	device_unregister(&adap->dev);

}
i2c-davinci.c是實現與硬件相關功能的代碼集合,這部分是與平臺相關的,也叫做i2c總線驅動,這部分代碼是這樣添加到系統中的
  1. static struct platform_driver davinci_i2c_driver = {  
  2.     .probe      = davinci_i2c_probe,  
  3.     .remove     = davinci_i2c_remove,  
  4.     .driver     = {  
  5.         .name   = "i2c_davinci",  
  6.         .owner  = THIS_MODULE,  
  7.     },  
  8. };  
  9.   
  10. /* I2C may be needed to bring up other drivers */  
  11. static int __init davinci_i2c_init_driver(void)  
  12. {  
  13.     return platform_driver_register(&davinci_i2c_driver);  
  14. }  
  15. subsys_initcall(davinci_i2c_init_driver);  
  16.   
  17. static void __exit davinci_i2c_exit_driver(void)  
  18. {  
  19.     platform_driver_unregister(&davinci_i2c_driver);  
  20. }  
  21. module_exit(davinci_i2c_exit_driver);  
static struct platform_driver davinci_i2c_driver = {
	.probe		= davinci_i2c_probe,
	.remove		= davinci_i2c_remove,
	.driver		= {
		.name	= "i2c_davinci",
		.owner	= THIS_MODULE,
	},
};

/* I2C may be needed to bring up other drivers */
static int __init davinci_i2c_init_driver(void)
{
	return platform_driver_register(&davinci_i2c_driver);
}
subsys_initcall(davinci_i2c_init_driver);

static void __exit davinci_i2c_exit_driver(void)
{
	platform_driver_unregister(&davinci_i2c_driver);
}
module_exit(davinci_i2c_exit_driver);
並且,i2c適配器控制硬件發送接收數據的函數在這裏賦值給i2c-algorithm,i2c_davinci_xfer稍加修改就可以在裸機中控制i2c適配器
  1. static struct i2c_algorithm i2c_davinci_algo = {  
  2.     .master_xfer    = i2c_davinci_xfer,  
  3.     .functionality  = i2c_davinci_func,  
  4. };  
static struct i2c_algorithm i2c_davinci_algo = {
	.master_xfer	= i2c_davinci_xfer,
	.functionality	= i2c_davinci_func,
};
然後在davinci_i2c_probe函數中,將i2c_davinci_algo添加到添加到algorithm系統中

  1. adap->algo = &i2c_davinci_algo;  
adap->algo = &i2c_davinci_algo;

梳理圖

有時候代碼比任何文字描述都來得直接,但是過多的代碼展示反而讓人覺得枯燥。這個時候,需要一幅圖來梳理一下上面的內容,請看圖3。


圖3

好了,上面這些代碼的展示是告訴我們,linux內核和芯片提供商爲我們的的驅動程序提供了 i2c驅動的框架,以及框架底層與硬件相關的代碼的實現。剩下的就是針對掛載在i2c兩線上的i2c設備了device,如at24c02,例如ov2715,而編寫的具體設備驅動了,這裏的設備就是硬件接口外掛載的設備,而非硬件接口本身(soc硬件接口本身的驅動可以理解爲總線驅動)。

在理解了i2c驅動架構後,我們接下來再作兩方面的分析工作:一是具體的i2c設備ov2715驅動源碼分析,二是davinci平臺的i2c總線驅動源碼。

ov2715設備i2c驅動源碼分析

ov2715爲200萬的CMOS Sensor,芯片的寄存器控制通過i2c接口完成,i2c設備地址爲0x6c,寄存器地址爲16位兩個字節,寄存器值爲8位一個字節,可以理解爲一般的字符設備。
該驅動程序並非只能用於ov2715,因此源碼中存在支持多個設備地址的機制。
該字符設備的用到的結構體有兩個,如下

  1. typedef struct {  
  2.   
  3.   int devAddr;  
  4.   
  5.   struct i2c_client client;   //!< Data structure containing general access routines.  
  6.   struct i2c_driver driver;   //!< Data structure containing information specific to each client.  
  7.     
  8.   char name[20];  
  9.   int nameSize;  
  10.   int users;  
  11.     
  12. } I2C_Obj;  
typedef struct {

  int devAddr;

  struct i2c_client client;   //!< Data structure containing general access routines.
  struct i2c_driver driver;   //!< Data structure containing information specific to each client.
  
  char name[20];
  int nameSize;
  int users;
  
} I2C_Obj;

  1. #define I2C_DEV_MAX_ADDR  (0xFF)  
  2. #define I2C_TRANSFER_BUF_SIZE_MAX   (256)  
  3. typedef struct {  
  4.   
  5.   struct cdev cdev;             /* Char device structure    */  
  6.   int     major;  
  7.   struct semaphore semLock;  
  8.       
  9.   I2C_Obj *pObj[I2C_DEV_MAX_ADDR];  
  10.   
  11.   uint8_t reg[I2C_TRANSFER_BUF_SIZE_MAX];  
  12.   uint16_t reg16[I2C_TRANSFER_BUF_SIZE_MAX];  
  13.   uint8_t buffer[I2C_TRANSFER_BUF_SIZE_MAX*4];  
  14.     
  15. } I2C_Dev;  
#define I2C_DEV_MAX_ADDR  (0xFF)
#define I2C_TRANSFER_BUF_SIZE_MAX   (256)
typedef struct {

  struct cdev cdev;             /* Char device structure    */
  int     major;
  struct semaphore semLock;
    
  I2C_Obj *pObj[I2C_DEV_MAX_ADDR];

  uint8_t reg[I2C_TRANSFER_BUF_SIZE_MAX];
  uint16_t reg16[I2C_TRANSFER_BUF_SIZE_MAX];
  uint8_t buffer[I2C_TRANSFER_BUF_SIZE_MAX*4];
  
} I2C_Dev;

一個I2C_Obj描述一個設備,devAddr保存該設備的地址,I2C_Obj內嵌到結構體I2C_Dev,I2C_Dev管理該驅動所支持的所有設備,儘管支持多個設備,但i2c適配器只有一個,因此需要一個信號量semLock來保護該共享資源,同時只能向一個設備讀寫數據。成員變量cdev是我們所熟知的,每個字符設備驅動中幾乎總會有一個結構體包含它,major用於保存該驅動的主設備編號,reg數組爲寄存器地址爲8位的寄存器地址緩衝區,reg16爲寄存器地址爲16的寄存器地址緩衝區。同時可以讀寫多個寄存器地址的值。buffer爲讀寫的寄存器值

使用I2C_Dev構建一個全局變量gI2C_dev,在驅動的多個地方均需要它。
下面先從字符設備的基本框架入手,然後深入該驅動的細節部分。
首先是該字符設備的初始化和退出函數

  1. int I2C_devInit(void)  
  2. {  
  3.   int     result, i;  
  4.   dev_t   dev = 0;  
  5.   
  6.   result = alloc_chrdev_region(&dev, 0, 1, I2C_DRV_NAME);//分配字符設備空間  
  7.     
  8.   for(i=0; i<I2C_DEV_MAX_ADDR; i++)  
  9.   {  
  10.     gI2C_dev.pObj[i]=NULL;  
  11.   }  
  12.   
  13.   gI2C_dev.major = MAJOR(dev);//保存設備主編號  
  14.   sema_init(&gI2C_dev.semLock, 1);//信號量初始化  
  15.   cdev_init(&gI2C_dev.cdev, &gI2C_devFileOps);//使用gI2C_devFileOps初始化該字符設備,gI2C_devFileOps見下文  
  16.   gI2C_dev.cdev.owner = THIS_MODULE;//常規賦值  
  17.  gI2C_dev.cdev.ops = &gI2C_devFileOps;//常規賦值 result = cdev_add(&gI2C_dev.cdev, dev, 1);//添加設備到字符設備中 return result;}void I2C_devExit(void){ dev_t devno = MKDEV(gI2C_dev.major, 0); cdev_del(&gI2C_dev.cdev);//從字符設備中刪除該設備 unregister_chrdev_region(devno, 1);//回收空間}  
  18. gI2c_devFileOps全局變量,驅動初始化會用到該結構體變量  
  19. struct file_operations gI2C_devFileOps = {  
  20.   .owner = THIS_MODULE,  
  21.   .open = I2C_devOpen,  
  22.   .release = I2C_devRelease,  
  23.   .ioctl = I2C_devIoctl,  
  24. };  
int I2C_devInit(void)
{
  int     result, i;
  dev_t   dev = 0;

  result = alloc_chrdev_region(&dev, 0, 1, I2C_DRV_NAME);//分配字符設備空間
  
  for(i=0; i<I2C_DEV_MAX_ADDR; i++)
  {
    gI2C_dev.pObj[i]=NULL;
  }

  gI2C_dev.major = MAJOR(dev);//保存設備主編號
  sema_init(&gI2C_dev.semLock, 1);//信號量初始化
  cdev_init(&gI2C_dev.cdev, &gI2C_devFileOps);//使用gI2C_devFileOps初始化該字符設備,gI2C_devFileOps見下文
  gI2C_dev.cdev.owner = THIS_MODULE;//常規賦值
 gI2C_dev.cdev.ops = &gI2C_devFileOps;//常規賦值 result = cdev_add(&gI2C_dev.cdev, dev, 1);//添加設備到字符設備中 return result;}void I2C_devExit(void){ dev_t devno = MKDEV(gI2C_dev.major, 0); cdev_del(&gI2C_dev.cdev);//從字符設備中刪除該設備 unregister_chrdev_region(devno, 1);//回收空間}
gI2c_devFileOps全局變量,驅動初始化會用到該結構體變量
struct file_operations gI2C_devFileOps = {
  .owner = THIS_MODULE,
  .open = I2C_devOpen,
  .release = I2C_devRelease,
  .ioctl = I2C_devIoctl,
};
該驅動只實現了三個函數,open,release和ioctl,對於i2c設備來說,這已經足夠了。
在I2C_devOpen和I2C_devOpen中並沒有做實際的工作,重要的工作均在I2C_devIoctl這個ioctl中完成。I2C_devIoctl代碼展示(將影響結構條理的代碼去掉,稍後在做詳細分析)

  1. int I2C_devIoctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
  2. {  
  3.   I2C_Obj *pObj;  
  4.   int status=0;  
  5.   I2C_TransferPrm transferPrm;  
  6.     
  7.   pObj = (I2C_Obj *)filp->private_data;  
  8.   
  9.   if(!I2C_IOCTL_CMD_IS_VALID(cmd))  
  10.     return -1;  
  11.   cmd = I2C_IOCTL_CMD_GET(cmd);//cmd命令轉換,防止混淆,具體原因參見上一篇文章:ioctl中的cmd  
  12.   
  13.   down_interruptible(&gI2C_dev.semLock);      //信號量down  
  14.     
  15.   switch(cmd)  
  16.   {  
  17.     case I2C_CMD_SET_DEV_ADDR://命令1,設置設備地址  
  18.       filp->private_data = I2C_create(arg);  
  19.   
  20.     case I2C_CMD_WRITE:  //命令2,寫寄存器值  
  21.         
  22.       status = copy_from_user(&transferPrm, (void *)arg, sizeof(transferPrm));  
  23.       ...  
  24.               
  25.       break;  
  26.     case I2C_CMD_READ:  //命令3,讀寄存器值  
  27.       
  28.       status = copy_from_user(&transferPrm, (void *)arg, sizeof(transferPrm));  
  29.       ...  
  30.         
  31.       break;  
  32.     default:  
  33.       status = -1;  
  34.       break;      
  35.   }  
  36.   
  37.   up(&gI2C_dev.semLock);      //信號量up  
  38.   
  39.   return status;  
  40. }  
int I2C_devIoctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
  I2C_Obj *pObj;
  int status=0;
  I2C_TransferPrm transferPrm;
  
  pObj = (I2C_Obj *)filp->private_data;

  if(!I2C_IOCTL_CMD_IS_VALID(cmd))
    return -1;
  cmd = I2C_IOCTL_CMD_GET(cmd);//cmd命令轉換,防止混淆,具體原因參見上一篇文章:ioctl中的cmd

  down_interruptible(&gI2C_dev.semLock);      //信號量down
  
  switch(cmd)
  {
    case I2C_CMD_SET_DEV_ADDR://命令1,設置設備地址
      filp->private_data = I2C_create(arg);

    case I2C_CMD_WRITE:  //命令2,寫寄存器值
      
      status = copy_from_user(&transferPrm, (void *)arg, sizeof(transferPrm));
      ...
            
      break;
    case I2C_CMD_READ:  //命令3,讀寄存器值
    
      status = copy_from_user(&transferPrm, (void *)arg, sizeof(transferPrm));
      ...
      
      break;
    default:
      status = -1;
      break;    
  }

  up(&gI2C_dev.semLock);      //信號量up

  return status;
}
以上三個命令中最重要最複雜的是第一個I2C_CMD_SET_DEV_ADDR,設置設備地址,之所以重要和複雜,因爲在I2C_create()函數中,將通過i2c-core提供的函數把該驅動程序和底層的i2c_adapter聯繫起來。下面是I2C_create()函數源碼

  1. void *I2C_create(int devAddr) {  
  2.   
  3.     int ret;  
  4.     struct i2c_driver *driver;  
  5.     struct i2c_client *client = client;  
  6.     I2C_Obj *pObj;  
  7.   
  8.     devAddr >>= 1;  
  9.       
  10.     if(devAddr>I2C_DEV_MAX_ADDR)  //變量合法性判斷  
  11.       return NULL;  
  12.      
  13.     if(gI2C_dev.pObj[devAddr]!=NULL) {  //變量合法性判斷,如果該地址的設備已經創建,則調過,防止上層錯誤調用  
  14.       // already allocated, increment user count, and return the allocated handle  
  15.       gI2C_dev.pObj[devAddr]->users++;  
  16.       return gI2C_dev.pObj[devAddr];  
  17.     }  
  18.       
  19.     pObj = (void*)kmalloc( sizeof(I2C_Obj), GFP_KERNEL); //爲pObj分配空間  
  20.     gI2C_dev.pObj[devAddr] = pObj;  //將分配的空間地址保存在全局變量裏  
  21.     memset(pObj, 0, sizeof(I2C_Obj));  
  22.     
  23.     pObj->client.adapter = NULL;  
  24.     pObj->users++;    //用戶基數,初始化爲0,當前設爲1   
  25.     pObj->devAddr = devAddr;  //保存設備地址  
  26.       
  27.     gI2C_curAddr = pObj->devAddr;  //gI2C_curAddr爲全局的整型變量,用於保存當前的設備地址  
  28.     driver = &pObj->driver;  //將成員變量driver單獨抽取出來,因爲線面要使用driver來初始化驅動  
  29.   
  30.     pObj->nameSize=0;//i2c設備名稱,注意,這裏不是在/dev下面的設備節點名  
  31.     pObj->name[pObj->nameSize++] = 'I';  
  32.     pObj->name[pObj->nameSize++] = '2';  
  33.     pObj->name[pObj->nameSize++] = 'C';  
  34.     pObj->name[pObj->nameSize++] = '_';     
  35.     pObj->name[pObj->nameSize++] = 'A' + ((pObj->devAddr >> 0) & 0xF);  
  36.     pObj->name[pObj->nameSize++] = 'B' + ((pObj->devAddr >> 4) & 0xF);  
  37.     pObj->name[pObj->nameSize++] = 0;  
  38.   
  39.     driver->driver.name = pObj->name; //保存剛纔設置的name  
  40.     driver->id = I2C_DRIVERID_MISC;  
  41.     driver->attach_adapter = I2C_attachAdapter;   //這個很重要,將驅動連接到i2c適配器上,在後面分析  
  42.     driver->detach_client = I2C_detachClient;    //這個很重,在後面分析  
  43.   
  44.     if((ret = i2c_add_driver(driver)))  //使用i2c-core(i2c_register_driver函數)的接口,註冊該驅動,i2c_add_driver實質調用了driver_register()  
  45.     {  
  46.         printk( KERN_ERR "I2C: ERROR: Driver registration failed (address=%x), module not inserted.\n", pObj->devAddr);  
  47.     }  
  48.   
  49.     if(ret<0) {  
  50.   
  51.       gI2C_dev.pObj[pObj->devAddr] = NULL;  
  52.       kfree(pObj);      
  53.       return NULL;  
  54.     }  
  55.     return pObj;  
  56. }  
void *I2C_create(int devAddr) {

    int ret;
    struct i2c_driver *driver;
    struct i2c_client *client = client;
    I2C_Obj *pObj;

    devAddr >>= 1;
    
    if(devAddr>I2C_DEV_MAX_ADDR)  //變量合法性判斷
      return NULL;
   
    if(gI2C_dev.pObj[devAddr]!=NULL) {	//變量合法性判斷,如果該地址的設備已經創建,則調過,防止上層錯誤調用
      // already allocated, increment user count, and return the allocated handle
      gI2C_dev.pObj[devAddr]->users++;
      return gI2C_dev.pObj[devAddr];
    }
    
    pObj = (void*)kmalloc( sizeof(I2C_Obj), GFP_KERNEL); //爲pObj分配空間
    gI2C_dev.pObj[devAddr] = pObj;  //將分配的空間地址保存在全局變量裏
    memset(pObj, 0, sizeof(I2C_Obj));
  
    pObj->client.adapter = NULL;
    pObj->users++;    //用戶基數,初始化爲0,當前設爲1
    pObj->devAddr = devAddr;  //保存設備地址
    
    gI2C_curAddr = pObj->devAddr;  //gI2C_curAddr爲全局的整型變量,用於保存當前的設備地址
    driver = &pObj->driver;  //將成員變量driver單獨抽取出來,因爲線面要使用driver來初始化驅動

    pObj->nameSize=0;//i2c設備名稱,注意,這裏不是在/dev下面的設備節點名
    pObj->name[pObj->nameSize++] = 'I';
    pObj->name[pObj->nameSize++] = '2';
    pObj->name[pObj->nameSize++] = 'C';
    pObj->name[pObj->nameSize++] = '_';   
    pObj->name[pObj->nameSize++] = 'A' + ((pObj->devAddr >> 0) & 0xF);
    pObj->name[pObj->nameSize++] = 'B' + ((pObj->devAddr >> 4) & 0xF);
    pObj->name[pObj->nameSize++] = 0;

    driver->driver.name = pObj->name; //保存剛纔設置的name
    driver->id = I2C_DRIVERID_MISC;
    driver->attach_adapter = I2C_attachAdapter;   //這個很重要,將驅動連接到i2c適配器上,在後面分析
    driver->detach_client = I2C_detachClient;	//這個很重,在後面分析

    if((ret = i2c_add_driver(driver)))	//使用i2c-core(i2c_register_driver函數)的接口,註冊該驅動,i2c_add_driver實質調用了driver_register()
    {
        printk( KERN_ERR "I2C: ERROR: Driver registration failed (address=%x), module not inserted.\n", pObj->devAddr);
    }

    if(ret<0) {

      gI2C_dev.pObj[pObj->devAddr] = NULL;
      kfree(pObj);    
      return NULL;
    }
    return pObj;
}

其他兩個命令是I2C_CMD_WRITE和I2C_CMD_READ,這個比較簡單,只需設置寄存器地址的大小以及寄存器值的大小,然後通過i2c-core 提供的i2c_transfer()函數發送即可。例如I2C_wirte()

  1. int I2C_write(I2C_Obj *pObj, uint8_t *reg, uint8_t *buffer, uint8_t count, uint8_t dataSize)  
  2. {  
  3.   uint8_t i;  
  4.   int err;  
  5.   struct i2c_client *client;  
  6.     struct i2c_msg msg[1];  
  7.     unsigned char data[8];  
  8.   
  9.   if(pObj==NULL)  
  10.     return -ENODEV;  
  11.   
  12.   client = &pObj->client;//得到client信息   
  13.   if(!client->adapter)  
  14.     return -ENODEV;    
  15.     
  16.   if(dataSize<=0||dataSize>4)  
  17.     return -1;  
  18.       
  19.   for(i=0; i<count; i++) {  
  20.     
  21.     msg->addr = client->addr;//設置要寫的i2c設備地址  
  22.     msg->flags= 0;//一直爲0   
  23.     msg->buf  = data;//date爲準備i2c通信的緩衝區,這個緩衝區除了不包含設備地址外,要包括要目標寄存器地址,和要寫入該寄存器的值  
  24.           
  25.     data[0] = reg[i];//寄存器地址賦值  
  26.           
  27.     if(dataSize==1) {//寄存器值長度爲1  
  28.        data[1]  = buffer[i];//寄存器值賦值   
  29.        msg->len = 2;     //設置data長度爲2      
  30.     }   else if(dataSize==2) {//寄存器值長度爲2  
  31.        data[1] = buffer[2*i+1];  
  32.        data[2] = buffer[2*i];  
  33.        msg->len = 3;  
  34.     }   
  35.     err = i2c_transfer(client->adapter, msg, 1);//調用i2c-core中的i2c_transfer發送i2c數據  
  36.     if( err < 0 )  
  37.       return err;  
  38.     }  
  39.     
  40.   return 0;  
  41. }  
int I2C_write(I2C_Obj *pObj, uint8_t *reg, uint8_t *buffer, uint8_t count, uint8_t dataSize)
{
  uint8_t i;
  int err;
  struct i2c_client *client;
	struct i2c_msg msg[1];
	unsigned char data[8];

  if(pObj==NULL)
    return -ENODEV;

  client = &pObj->client;//得到client信息
  if(!client->adapter)
    return -ENODEV;  
  
  if(dataSize<=0||dataSize>4)
    return -1;
    
  for(i=0; i<count; i++) {
  
    msg->addr = client->addr;//設置要寫的i2c設備地址
    msg->flags= 0;//一直爲0
    msg->buf  = data;//date爲準備i2c通信的緩衝區,這個緩衝區除了不包含設備地址外,要包括要目標寄存器地址,和要寫入該寄存器的值
		
    data[0] = reg[i];//寄存器地址賦值
		
    if(dataSize==1) {//寄存器值長度爲1
       data[1]  = buffer[i];//寄存器值賦值
       msg->len = 2;  	//設置data長度爲2	
    }	else if(dataSize==2) {//寄存器值長度爲2
       data[1] = buffer[2*i+1];
       data[2] = buffer[2*i];
       msg->len = 3;
    } 
    err = i2c_transfer(client->adapter, msg, 1);//調用i2c-core中的i2c_transfer發送i2c數據
    if( err < 0 )
      return err;
    }
  
  return 0;
}

現在,我們重點分析上一段代碼void *I2C_create(int devAddr)函數中的i2c_driver結構體部分的代碼,下面的代碼是從上面I2C_create抽取出來的

  1. driver->driver.name = pObj->name;  
  2. driver->id = I2C_DRIVERID_MISC;  
  3. driver->attach_adapter = I2C_attachAdapter;  
  4. driver->detach_client = I2C_detachClient;  
    driver->driver.name = pObj->name;
    driver->id = I2C_DRIVERID_MISC;
    driver->attach_adapter = I2C_attachAdapter;
    driver->detach_client = I2C_detachClient;
在i2c_driver結構體中針對attach_adapter有這樣的說明:

  1. /* Notifies the driver that a new bus has appeared. This routine 
  2.  * can be used by the driver to test if the bus meets its conditions 
  3.  * & seek for the presence of the chip(s) it supports. If found, it  
  4.  * registers the client(s) that are on the bus to the i2c admin. via 
  5.  * i2c_attach_client. 
  6.  */  
	/* Notifies the driver that a new bus has appeared. This routine
	 * can be used by the driver to test if the bus meets its conditions
	 * & seek for the presence of the chip(s) it supports. If found, it 
	 * registers the client(s) that are on the bus to the i2c admin. via
	 * i2c_attach_client.
	 */
意思是通知驅動,i2c適配器已經就緒了,這時可以講device的driver連接到總線bus上。所以I2C_attachAdapter的作用就是檢測client,然後將client連接上來。attach_adapter和detach_client由內核驅動自動調用,我們只需在調用的時候實現必要的功能即可,如下代碼展示
  1. int I2C_attachAdapter(struct i2c_adapter *adapter)  
  2. {  
  3.     return I2C_detectClient(adapter, gI2C_curAddr);  
  4. }  
  5.   
  6. int I2C_detectClient(struct i2c_adapter *adapter, int address)  
  7. {  
  8.     I2C_Obj *pObj;  
  9.     struct i2c_client *client;  
  10.     int err = 0;  
  11.       
  12.     if(address > I2C_DEV_MAX_ADDR) {  
  13.       printk( KERN_ERR "I2C: ERROR: Invalid device address %x\n", address);          
  14.       return -1;  
  15.     }  
  16.         
  17.     pObj = gI2C_dev.pObj[address];  
  18.     if(pObj==NULL) {  
  19.       printk( KERN_ERR "I2C: ERROR: Object not found for address %x\n", address);      
  20.       return -1;  
  21.     }  
  22.   
  23.     client = &pObj->client;  
  24.   
  25.     if(client->adapter)  
  26.       return -EBUSY;  /* our client is already attached */  
  27.   
  28.     memset(client, 0x00, sizeof(struct i2c_client));  
  29.     client->addr = pObj->devAddr;  
  30.     client->adapter = adapter;  
  31.     client->driver = &pObj->driver;  
  32.   
  33.     if((err = i2c_attach_client(client)))  
  34.     {  
  35.         printk( KERN_ERR "I2C: ERROR: Couldn't attach %s (address=%x)\n", pObj->name, pObj->devAddr);  
  36.         client->adapter = NULL;  
  37.         return err;  
  38.     }  
  39.     return 0;  
  40. }  
int I2C_attachAdapter(struct i2c_adapter *adapter)
{
    return I2C_detectClient(adapter, gI2C_curAddr);
}

int I2C_detectClient(struct i2c_adapter *adapter, int address)
{
    I2C_Obj *pObj;
    struct i2c_client *client;
    int err = 0;
    
    if(address > I2C_DEV_MAX_ADDR) {
      printk( KERN_ERR "I2C: ERROR: Invalid device address %x\n", address);        
      return -1;
    }
      
    pObj = gI2C_dev.pObj[address];
    if(pObj==NULL) {
      printk( KERN_ERR "I2C: ERROR: Object not found for address %x\n", address);    
      return -1;
    }

    client = &pObj->client;

    if(client->adapter)
      return -EBUSY;  /* our client is already attached */

    memset(client, 0x00, sizeof(struct i2c_client));
    client->addr = pObj->devAddr;
    client->adapter = adapter;
    client->driver = &pObj->driver;

    if((err = i2c_attach_client(client)))
    {
        printk( KERN_ERR "I2C: ERROR: Couldn't attach %s (address=%x)\n", pObj->name, pObj->devAddr);
        client->adapter = NULL;
        return err;
    }
    return 0;
}
最終I2C_detectClient()函數調用了i2c-core中的i2c_attach_client,從名字上就能看出什麼意思,連接client設備。
當內核驅動準備刪除該驅動時會自動調用i2c_driver的成員函數:detech_client,因此我們需要實現刪除client設備的函數然後賦值給改函數指針,detech_client的說明如下:

  1. /* tells the driver that a client is about to be deleted & gives it  
  2.  * the chance to remove its private data. Also, if the client struct 
  3.  * has been dynamically allocated by the driver in the function above, 
  4.  * it must be freed here. 
  5.  */  
	/* tells the driver that a client is about to be deleted & gives it 
	 * the chance to remove its private data. Also, if the client struct
	 * has been dynamically allocated by the driver in the function above,
	 * it must be freed here.
	 */
下面是detech_client調用的函數代碼清單,該函數最終調用了i2c-core提供的i2c_detach_client,用於取消client設備的連接

  1. int I2C_detachClient(struct i2c_client *client)  
  2. {  
  3.     int err;  
  4.   
  5.     if(!client->adapter)  
  6.         return -ENODEV; /* our client isn't attached */  
  7.   
  8.     if((err = i2c_detach_client(client))) {  
  9.         printk( KERN_ERR "Client deregistration failed (address=%x), client not detached.\n", client->addr);  
  10.         return err;  
  11.     }  
  12.   
  13.     client->adapter = NULL;  
  14.   
  15.     return 0;  
  16. }  
int I2C_detachClient(struct i2c_client *client)
{
    int err;

    if(!client->adapter)
        return -ENODEV; /* our client isn't attached */

    if((err = i2c_detach_client(client))) {
        printk( KERN_ERR "Client deregistration failed (address=%x), client not detached.\n", client->addr);
        return err;
    }

    client->adapter = NULL;

    return 0;
}

ov2715設備的i2c驅動源碼的分析就到這裏,至於平臺相關的i2c總線驅動分析就放到下一篇文章裏分析,因爲這部分多數情況下並不需要我們親自去實現。但是對於理解i2c驅動架構來說,還是有很大幫助的。

 

 

 

 

其他文章:

Linux 設備驅動篇之I2c設備驅動
fulinux
一、I2C驅動體系

雖然I2C硬件體系結構和協議都很容易理解,但是Linux I2C驅動體系結構卻有相當的複雜度,它主要由3部分組成,即I2C設備驅動、I2C總線驅動和I2C核心。

1.I2C核心

I2C核心是I2c總線和I2c設備驅動的中間樞紐,它以通用的、與平臺無關的接口實現了I2C中設備與適配器的溝通,提供了I2C總線驅動和設備驅動的註冊、註銷方法,I2C通信方法(即“algorithm”)上層的、與具體適配器無關的代碼以及探測設備、檢測設備的地址的上層代碼等。I2c總線驅動填充I2c_adapterI2c_algorithm結構體,I2c設備驅動填充I2c_driveri2c_client結構體並實現其本身所對應設備類型的驅動。

2.I2C總線驅動

I2C總線驅動是對I2C硬件體系結構中適配器的實現,適配器可由CPU控制,甚至可以直接集成在CPU內部。

I2C總線驅動主要包含了I2C適配器數據結構i2c_adapterI2C適配器的algorithm數據結構i2c_algorithm和控制I2C適配器產生通信信號的函數。

經由I2C總線驅動的代碼,我們可以控制I2C適配器以主控制方式產生開始、停止位、讀寫週期,以及以從設備方式讀寫、產生ACK等。

3.I2C設備驅動

I2C設備驅動(也稱爲客戶端驅動)是對I2C硬件體系結構中設備端的實現,設備一般掛接在受CPU控制的I2C適配器上,通過I2C適配器與CPU交換數據。

I2C設備驅動主要包含了數據結構體i2c_driveri2c_client,我們需要具體設備實現其中的成員函數。

 

1 I2C驅動體系結構圖1

 

2 I2C驅動體系結構圖2

另外,系統中i2c-dev.c文件定義的主設備號爲89的設備可以方便地給應用程序提供讀寫I2c設備寄存器的能力,使得工程師大多數時候並不需要爲具體的I2c設備驅動定義文件操作接口。

如何理解adapterclient呢?它在s3c2440中對應的是什麼?Adapterclient都是linux驅動軟件抽象出來的東西,Linux I2C框架搞那麼複雜是爲了通用性及爲了符合Linux內核驅動模式而制定的。簡單的說,你的開發板上有幾個I2C接口,就有幾個adapter , 也就是有幾條I2C bus , I2C client對應的就是你的外圍I2C 設備,有幾個就有幾個client , 把這些設備插入開發板, 對應其中的一條bus, 那麼相應的就對應了其中的一個adapter , 接下來的就是I2c核心部分使client與 adapter匹配成對。

在linux內核中,所有的I2C設備都在sysfs文件系統中顯示,存在於/sys/bus/i2c/目錄下,適配器地址和芯片地址的形式列出,例如:

1. [fulinux@ubuntu linux-3.0]$ tree /sys/bus/i2c/       

2. /sys/bus/i2c/

3. |-- devices

4. |   |-- i2c-0 -> ../../../devices/pci0000:00/0000:00:02.0/i2c-0

5. |   |-- i2c-1 -> ../../../devices/pci0000:00/0000:00:02.0/i2c-1

6. |   |-- i2c-2 -> ../../../devices/pci0000:00/0000:00:02.0/i2c-2

7. |   |-- i2c-3 -> ../../../devices/pci0000:00/0000:00:02.0/i2c-3

8. |   |-- i2c-4 -> ../../../devices/pci0000:00/0000:00:02.0/i2c-4

9. |   |-- i2c-5 -> ../../../devices/pci0000:00/0000:00:02.0/i2c-5

10. |   |-- i2c-6 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card0/card0-DP-1/i2c-6

11. |   `-- i2c-7 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card0/card0-DP-2/i2c-7

12. |-- drivers

13. |   |-- 88PM860x

14. |   |   |-- bind

15. |   |   |-- uevent

16. |   |   `-- unbind

17. |   |-- aat2870

18. |   |   |-- bind

19. |   |   |-- uevent

20. |   |   `-- unbind

21. |   |-- ab3100

22. |   |   |-- bind

23. |   |   |-- uevent

24. |   |   `-- unbind

25. |   |-- adp5520

下面我以s3c2440開發板及其之上的EEPROM芯片AT24C02linux-3.0內核平臺講解I2c的三個部分。

********************************************************************************************

轉載聲明:希望大家能轉載此文謝謝  原文鏈接

********************************************************************************************

4.s3c2440at24c02硬件特性

請看s3c2440.pdf

芯片AT24C02的電氣特性:

• Low-voltage and Standard-voltage Operation

– 2.7 (VCC= 2.7V to 5.5V)

– 1.8 (VCC= 1.8V to 5.5V)

• Internally Organized 128 x 8 (1K), 256 x 8 (2K), 512 x 8 (4K),

1024 x 8 (8K) or 2048 x 8 (16K)

• Two-wire Serial Interface

• Schmitt Trigger, Filtered Inputs for Noise Suppression

• Bidirectional Data Transfer Protocol

• 100 kHz (1.8V) and 400 kHz (2.7V, 5V) Compatibility

• Write Protect Pin for Hardware Data Protection

• 8-byte Page (1K, 2K), 16-byte Page (4K, 8K, 16K) Write Modes

• Partial Page Writes Allowed

• Self-timed Write Cycle (5 ms max)

• High-reliability

– Endurance: 1 Million Write Cycles

– Data Retention: 100 Years

• Automotive Grade and Lead-free/Halogen-free Devices Available

• 8-lead PDIP, 8-lead JEDEC SOIC, 8-lead MAP, 5-lead SOT23,

8-lead TSSOP and 8-ball dBGA2 Packages

• Die Sales: Wafer Form, Waffle Pack and Bumped Wafers

主要是看AT24C02.pdf

3 S3c244開發板核心板電路圖

圖4 AT24C02電路圖

5.i2c.h頭文件

內核中i2c.h這個頭文件對i2c_driveri2c_clienti2c_adapteri2c_algorithm4個數據結構進行了定義。理解這4個結構的作用十分關鍵,代碼清單1234分別給出了它們的定義。

代碼清單1 i2c_adapter結構體

1. /*

2.  * i2c_adapter is the structure used to identify a physical i2c bus along

3.  * with the access algorithms necessary to access it.

4.  */

5. struct i2c_adapter {

6.     struct module *owner;

7.     unsigned int class;       /* classes to allow probing for */

8.     const struct i2c_algorithm *algo; /* the algorithm to access the bus */

9.     void *algo_data;

10.     /* data fields that are valid for all devices   */

11.     struct rt_mutex bus_lock;

12.     int timeout;            /* in jiffies */

13.     int retries;

14.     struct device dev;      /* the adapter device */

15.     int nr;

16.     char name[48];

17.     struct completion dev_released;

18.     struct mutex userspace_clients_lock;

19.     struct list_head userspace_clients;

20. };

代碼清單2 i2c_algorithm結構體

1. /*

2.  * The following structs are for those who like to implement new bus drivers:

3.  * i2c_algorithm is the interface to a class of hardware solutions which can

4.  * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584

5.  * to name two of the most common.

6.  */

7. struct i2c_algorithm {

8.     /* If an adapter algorithm can't do I2C-level access, set master_xfer

9.        to NULL. If an adapter algorithm can do SMBus access, set

10.        smbus_xfer. If set to NULL, the SMBus protocol is simulated

11.        using common I2C messages */

12.     /* master_xfer should return the number of messages successfully

13.        processed, or a negative value on error */

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

15.                int num);

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

17.                unsigned short flags, char read_write,

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

19.     /* To determine what the adapter supports */

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

21. };

上述代碼第4行對應爲SMBus傳輸函數指針,SMBus大部分基於I2C總線規範,SMBus不需要增加額外引腳。與I2C總線相比,SMBus增加了一些新的功能特性,在訪問時序也有一定的差異。

代碼清單3 i2c_driver結構體

1. /*

2.  * struct i2c_driver - represent an I2C device driver

3.  * @class: What kind of i2c device we instantiate (for detect)

4.  * @attach_adapter: Callback for bus addition (deprecated)

5.  * @detach_adapter: Callback for bus removal (deprecated)

6.  * @probe: Callback for device binding

7.  * @remove: Callback for device unbinding

8.  * @shutdown: Callback for device shutdown

9.  * @suspend: Callback for device suspend

10.  * @resume: Callback for device resume

11.  * @alert: Alert callback, for example for the SMBus alert protocol

12.  * @command: Callback for bus-wide signaling (optional)

13.  * @driver: Device driver model driver

14.  * @id_table: List of I2C devices supported by this driver

15.  * @detect: Callback for device detection

16.  * @address_list: The I2C addresses to probe (for detect)

17.  * @clients: List of detected clients we created (for i2c-core use only)

18.  *

19.  * The driver.owner field should be set to the module owner of this driver.

20.  * The driver.name field should be set to the name of this driver.

21.  *

22.  * For automatic device detection, both @detect and @address_data must

23.  * be defined. @class should also be set, otherwise only devices forced

24.  * with module parameters will be created. The detect function must

25.  * fill at least the name field of the i2c_board_info structure it is

26.  * handed upon successful detection, and possibly also the flags field.

27.  *

28.  * If @detect is missing, the driver will still work fine for enumerated

29.  * devices. Detected devices simply won't be supported. This is expected

30.  * for the many I2C/SMBus devices which can't be detected reliably, and

31.  * the ones which can always be enumerated in practice.

32.  *

33.  * The i2c_client structure which is handed to the @detect callback is

34.  * not a real i2c_client. It is initialized just enough so that you can

35.  * call i2c_smbus_read_byte_data and friends on it. Don't do anything

36.  * else with it. In particular, calling dev_dbg and friends on it is

37.  * not allowed.

38.  */

39. struct i2c_driver {

40.     unsigned int class;

41.     /* Notifies the driver that a new bus has appeared or is about to be

42.      * removed. You should avoid using this, it will be removed in a

43.      * near future.

44.      */

45.     int (*attach_adapter)(struct i2c_adapter *) __deprecated;

46.     int (*detach_adapter)(struct i2c_adapter *) __deprecated;

47.     /* Standard driver model interfaces */

48.     int (*probe)(struct i2c_client *, const struct i2c_device_id *);

49.     int (*remove)(struct i2c_client *);

50.     /* driver model interfaces that don't relate to enumeration  */

51.     void (*shutdown)(struct i2c_client *);

52.     int (*suspend)(struct i2c_client *, pm_message_t mesg);

53.     int (*resume)(struct i2c_client *);

54.     /* Alert callback, for example for the SMBus alert protocol.

55.      * The format and meaning of the data value depends on the protocol.

56.      * For the SMBus alert protocol, there is a single bit of data passed

57.      * as the alert response's low bit ("event flag").

58.      */

59.     void (*alert)(struct i2c_client *, unsigned int data);

60.     /* a ioctl like command that can be used to perform specific functions

61.      * with the device.

62.      */

63.     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

64.     struct device_driver driver;

65.     const struct i2c_device_id *id_table;

66.     /* Device detection callback for automatic device creation */

67.     int (*detect)(struct i2c_client *, struct i2c_board_info *);

68.     const unsigned short *address_list;

69.     struct list_head clients;

70. };

代碼清單4 i2c_client結構體

1. /*

2.  * struct i2c_client - represent an I2C slave device

3.  * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;

4.  *  I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking

5.  * @addr: Address used on the I2C bus connected to the parent adapter.

6.  * @name: Indicates the type of the device, usually a chip name that's

7.  *  generic enough to hide second-sourcing and compatible revisions.

8.  * @adapter: manages the bus segment hosting this I2C device

9.  * @driver: device's driver, hence pointer to access routines

10.  * @dev: Driver model device node for the slave.

11.  * @irq: indicates the IRQ generated by this device (if any)

12.  * @detected: member of an i2c_driver.clients list or i2c-core's

13.  *  userspace_devices list

14.  *

15.  * An i2c_client identifies a single device (i.e. chip) connected to an

16.  * i2c bus. The behaviour exposed to Linux is defined by the driver

17.  * managing the device.

18.  */

19. struct i2c_client {

20.     unsigned short flags;       /* div., see below      */

21.     unsigned short addr;        /* chip address - NOTE: 7bit    */

22.                     /* addresses are stored in the  */

23.                     /* _LOWER_ 7 bits       */

24.     char name[I2C_NAME_SIZE];

25.     struct i2c_adapter *adapter;    /* the adapter we sit on    */

26.     struct i2c_driver *driver;  /* and our access routines  */

27.     struct device dev;      /* the device structure     */

28.     int irq;            /* irq issued by device     */

29.     struct list_head detected;

30. };

下面分析i2c_driveri2c_clienti2c_adapteri2c_algorithm4個數據結構的作用及盤根錯節的關係。

(1)2c_adapteri2c_algorithm

i2c_adapter對應於物理上的一個適配器,而i2c_algorithm對應一套通信方法。一個I2C適配器需要i2c_algorithm中提供的通信函數來控制適配器上產生特定的訪問週期。缺少i2c_algorithmi2c_adapter什麼也做不了,因此i2c_adapter中包含其使用的i2c_algorithm的指針。

I2c_algorithm中關鍵函數master_xfer用於產生I2C訪問週期需要的信號,以i2c_msg(即I2C消息)爲單位。I2c_msg結構體非常關鍵,代碼清單5給出了它的定義。

代碼清單5 i2c_msg結構體

/**

 * struct i2c_msg - an I2C transaction segment beginning with START

 * @addr: Slave address, either seven or ten bits.  When this is a ten

 *  bit address, I2C_M_TEN must be set in @flags and the adapter

 *  must support I2C_FUNC_10BIT_ADDR.

 * @flags: I2C_M_RD is handled by all adapters.  No other flags may be

 *  provided unless the adapter exported the relevant I2C_FUNC_*

 *  flags through i2c_check_functionality().

 * @len: Number of data bytes in @buf being read from or written to the

 *  I2C slave address.  For read transactions where I2C_M_RECV_LEN

 *  is set, the caller guarantees that this buffer can hold up to

 *  32 bytes in addition to the initial length byte sent by the

 *  slave (plus, if used, the SMBus PEC); and this value will be

 *  incremented by the number of block data bytes received.

 * @buf: The buffer into which data is read, or from which it's written.

 *

 * An i2c_msg is the low level representation of one segment of an I2C

 * transaction.  It is visible to drivers in the @i2c_transfer() procedure,

 * to userspace from i2c-dev, and to I2C adapter drivers through the

 * @i2c_adapter.@master_xfer() method.

 *

 * Except when I2C "protocol mangling" is used, all I2C adapters implement

 * the standard rules for I2C transactions.  Each transaction begins with a

 * START.  That is followed by the slave address, and a bit encoding read

 * versus write.  Then follow all the data bytes, possibly including a byte

 * with SMBus PEC.  The transfer terminates with a NAK, or when all those

 * bytes have been transferred and ACKed.  If this is the last message in a

 * group, it is followed by a STOP.  Otherwise it is followed by the next

 * @i2c_msg transaction segment, beginning with a (repeated) START.

 *

 * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then

 * passing certain @flags may have changed those standard protocol behaviors.

 * Those flags are only for use with broken/nonconforming slaves, and with

 * adapters which are known to support the specific mangling options they

 * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).

 */

struct i2c_msg {

    __u16 addr; /* slave address            */

    __u16 flags;

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

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

#define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */

#define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */

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

    __u16 len;      /* msg length               */

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

};

(2)i2c_driveri2c_client

i2c_driver對應一套驅動方法,其主要成員函數是probe()、remove()、suspend()resume()等,另外id_table是該驅動所支持的I2C設備的ID表。i2c_client對應於真實的物理設備,每個I2C設備都需要一個i2c_client來描述。I2c_driveri2c_client的關係是一對多,一個i2c_driver上可以支持多個同類型的i2c_client

I2c_client信息通常在BSP的板文件中通過i2c_board_info填充,如下面代碼就定義了一個I2C設備ID爲“24c02”、地址爲0x50i2c_client:

代碼清單6 i2c_board_info結構體定義

1. static struct i2c_board_info __initdata smdk2440_i2c_devs[] = {

2.     {

3.         I2C_BOARD_INFO("24c02", 0x50),

4.         .platform_data = &at24c02,

5.     },

6.     /*  more devices can be added using expansion connectors */

7. };

I2C總線驅動i2c_bus_typematch()函數i2c_device_match()中,會調用i2c_match_id()函數匹配板文件中定義的IDi2c_driver所支持的ID表。

代碼清單7 i2c_device_match函數在linux-3.0/drivers/i2c/i2c-core.c

1. static int i2c_device_match(struct device *dev, struct device_driver *drv)

2. {

3.     struct i2c_client   *client = i2c_verify_client(dev);

4.     struct i2c_driver   *driver;

5.     if (!client)

6.         return 0;

7.     /* Attempt an OF style match */

8.     if (of_driver_match_device(dev, drv))

9.         return 1;

10.     driver = to_i2c_driver(drv);

11.     /* match on an id table if there is one */

12.     if (driver->id_table)

13.         return i2c_match_id(driver->id_table, client) != NULL;

14.     return 0;

15. }

(3)i2c_adpateri2c_client

i2c_adapteri2c_client的關係與I2C硬件體系中適配器和設備的關係一致,即i2c_client依附於i2c_adapter。由於一個適配器上可以連接多個I2C設備,所以一個i2c_adapter也可以被多個i2c_client依附,i2c_adapter中包含依附於它的i2c_client的鏈表。

代碼清單8 i2c_client的鏈表

1. struct list_head userspace_clients;

假設I2C總線適配器xxx上有兩個使用相同驅動程序的yyyI2C設備,在打開I2C總線的設備節點後相關數據結構之間的邏輯組織關係將如下圖所示:

 

5 I2C總線的設備節點後相關數據結構之間的邏輯組織關係圖

從上面的分析可知,雖然I2C硬件體系結構簡單,但是I2C體系結構在linux中的實現卻相當複雜。當工程師拿到實際的電路板,面對複雜的linux I2C子系統,應該如何下手寫驅動呢?究竟要哪些是需要親自做的,哪些是內核已經提供的呢?理清這個問題非常有意義,可以使我們面對具體問題時迅速地抓住重點。

一方面,適配器驅動可能是linux內核本身還不包含的;另一方面,掛接在適配器上的就提設備可能也是linux內核還不包含的。因此,工程師要實現的主要工作如下。

提供I2C適配器的硬件驅動,探測、初始化I2C適配器(如申請I2CI/O地址和中斷號)、驅動CPU控制的I2C適配器從硬件上產生各種信號以及處理I2C中斷等。

提供I2C適配器的algorithm,具體適配器的xxx_xfer()函數填充i2c_algorithmmaster_xfer指針,並把i2c_algorithm指針賦值給i2c_adapteralgo指針。

實現I2C設備驅動中的i2c_driver接口,具體設備yyy_probe()yyy_remove()yyy_suspend()yyy_resume()函數指針和i2c_device_id設備ID表賦值給i2c_driverproberemovesuspendresumeid_table指針。

實現I2C設備所對應類型的具體驅動,i2c_driver只是實現設備與總線的掛接,而掛接在總線上的設備則是千差萬別的。例如,如果字符設備,就實現文件操作接口,即實現具體yyyyyy_read()yyy_write()yyy_ioctl()函數等;如果是聲卡,就實現ALSA驅動。

二、I2C的第一部分
1.Linux I2C核心

I2C核心(driver/i2c/i2c-core.c)文件中提供了一組不依賴與硬件平臺的接口函數,這個文件一般不需要被工程師修改,但是理解其中的主要函數非常關鍵,因爲I2C總線驅動和設備驅動之間依賴於I2C核心作爲紐帶I2C核心中的主要函數如下。

2.增加/刪除i2c_adapter

代碼清單9 i2c_add_adapter函數:

1. /**

2.  * i2c_add_adapter - declare i2c adapter, use dynamic bus number

3.  * @adapter: the adapter to add

4.  * Context: can sleep

5.  *

6.  * This routine is used to declare an I2C adapter when its bus number

7.  * doesn't matter.  Examples: for I2C adapters dynamically added by

8.  * USB links or PCI plugin cards.

9.  *

10.  * When this returns zero, a new bus number was allocated and stored

11.  * in adap->nr, and the specified adapter became available for clients.

12.  * Otherwise, a negative errno value is returned.

13.  */

14. int i2c_add_adapter(struct i2c_adapter *adapter)

15. {

16.     int id, res = 0;

17. retry:

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

19.         return -ENOMEM;

20.     mutex_lock(&core_lock);

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

22.     res = idr_get_new_above(&i2c_adapter_idr, adapter,

23.                 __i2c_first_dynamic_bus_num, &id);

24.     mutex_unlock(&core_lock);

25.     if (res < 0) {

26.         if (res == -EAGAIN)

27.             goto retry;

28.         return res;

29.     }

30.     adapter->nr = id;

31.     return i2c_register_adapter(adapter);

32. }

33. EXPORT_SYMBOL(i2c_add_adapter);

代碼清單10 I2c_del_adapter函數:

1. /**

2.  * i2c_del_adapter - unregister I2C adapter

3.  * @adap: the adapter being unregistered

4.  * Context: can sleep

5.  *

6.  * This unregisters an I2C adapter which was previously registered

7.  * by @i2c_add_adapter or @i2c_add_numbered_adapter.

8.  */

9. int i2c_del_adapter(struct i2c_adapter *adap)

10. {

11.     int res = 0;

12.     struct i2c_adapter *found;

13.     struct i2c_client *client, *next;

14.     /* First make sure that this adapter was ever added */

15.     mutex_lock(&core_lock);

16.     found = idr_find(&i2c_adapter_idr, adap->nr);

17.     mutex_unlock(&core_lock);

18.     if (found != adap) {

19.         pr_debug("i2c-core: attempting to delete unregistered "

20.              "adapter [%s]\n", adap->name);

21.         return -EINVAL;

22.     }

23.     /* Tell drivers about this removal */

24.     mutex_lock(&core_lock);

25.     res = bus_for_each_drv(&i2c_bus_type, NULL, adap,

26.                    __process_removed_adapter);

27.     mutex_unlock(&core_lock);

28.     if (res)

29.         return res;

30.     /* Remove devices instantiated from sysfs */

31.     mutex_lock(&adap->userspace_clients_lock);

32.     list_for_each_entry_safe(client, next, &adap->userspace_clients,

33.                  detected) {

34.         dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,

35.             client->addr);

36.         list_del(&client->detected);

37.         i2c_unregister_device(client);

38.     }

39.     mutex_unlock(&adap->userspace_clients_lock);

40. 

41.     /* Detach any active clients. This can't fail, thus we do not

42.      * check the returned value. This is a two-pass process, because

43.      * we can't remove the dummy devices during the first pass: they

44.      * could have been instantiated by real devices wishing to clean

45.      * them up properly, so we give them a chance to do that first. */

46.     res = device_for_each_child(&adap->dev, NULL, __unregister_client);

47.     res = device_for_each_child(&adap->dev, NULL, __unregister_dummy);

48. 

49. #ifdef CONFIG_I2C_COMPAT

50.     class_compat_remove_link(i2c_adapter_compat_class, &adap->dev,

51.                  adap->dev.parent);

52. #endif

53. 

54.     /* device name is gone after device_unregister */

55.     dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);

56. 

57.     /* clean up the sysfs representation */

58.     init_completion(&adap->dev_released);

59.     device_unregister(&adap->dev);

60. 

61.     /* wait for sysfs to drop all references */

62.     wait_for_completion(&adap->dev_released);

63. 

64.     /* free bus id */

65.     mutex_lock(&core_lock);

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

67.     mutex_unlock(&core_lock);

68. 

69.     /* Clear the device structure in case this adapter is ever going to be

70.        added again */

71.     memset(&adap->dev, 0, sizeof(adap->dev));

72. 

73.     return 0;

74. }

75. EXPORT_SYMBOL(i2c_del_adapter);

3.增加/刪除i2c_driver

代碼清單11 I2c_register_driver函數:

1. static int i2c_register_adapter(struct i2c_adapter *adap)

2. {

3.     int res = 0;

4. 

5.     /* Can't register until after driver model init */

6.     if (unlikely(WARN_ON(!i2c_bus_type.p))) {

7.         res = -EAGAIN;

8.         goto out_list;

9.     }  

10. 

11.     /* Sanity checks */

12.     if (unlikely(adap->name[0] == '\0')) {   

13.         pr_err("i2c-core: Attempt to register an adapter with "

14.                "no name!\n");

15.         return -EINVAL;

16.     }  

17.     if (unlikely(!adap->algo)) {        

18.         pr_err("i2c-core: Attempt to register adapter '%s' with "

19.                "no algo!\n", adap->name);        

20.         return -EINVAL;

21.     }  

22. 

23.     rt_mutex_init(&adap->bus_lock);     

24.     mutex_init(&adap->userspace_clients_lock);

25.     INIT_LIST_HEAD(&adap->userspace_clients);

26. 

27.     /* Set default timeout to 1 second if not already set */

28.     if (adap->timeout == 0)

29.         adap->timeout = HZ;             

30. 

31.     dev_set_name(&adap->dev, "i2c-%d", adap->nr);

32.     adap->dev.bus = &i2c_bus_type;

33.     adap->dev.type = &i2c_adapter_type;

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

35.     if (res)

36.         goto out_list;

37. 

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

39. 

40. #ifdef CONFIG_I2C_COMPAT

41.     res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,

42.                        adap->dev.parent);

43.     if (res)

44.         dev_warn(&adap->dev,

45.              "Failed to create compatibility class link\n");

46. #endif

47. 

48.     /* create pre-declared device nodes */

49.     if (adap->nr < __i2c_first_dynamic_bus_num)

50.         i2c_scan_static_board_info(adap);

51. 

52.     /* Notify drivers */

53.     mutex_lock(&core_lock);

54.     bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);

55.     mutex_unlock(&core_lock);

56. 

57.     return 0;

58. 

59. out_list:

60.     mutex_lock(&core_lock);

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

62.     mutex_unlock(&core_lock);

63.     return res;

64. }

代碼清單12 i2c_del_driver函數:

1. /*

2.  * i2c_del_driver - unregister I2C driver

3.  * @driver: the driver being unregistered

4.  * Context: can sleep

5.  */

6. void i2c_del_driver(struct i2c_driver *driver)

7. {

8.     i2c_for_each_dev(driver, __process_removed_driver);

9. 

10.     driver_unregister(&driver->driver);

11.     pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);

12. }

13. EXPORT_SYMBOL(i2c_del_driver);

4.i2c_client依附/脫離

當一個具體的client被偵測到並被關聯的時候,設備和使用爽膚水文件件被註冊。相反地,在client杯取消關聯的時候,sysfs文件和設備也被註銷。如下代碼清單13

代碼清單13 i2c_new_device函數:

1. /**

2.  * i2c_new_device - instantiate an i2c device

3.  * @adap: the adapter managing the device

4.  * @info: describes one I2C device; bus_num is ignored

5.  * Context: can sleep

6.  *

7.  * Create an i2c device. Binding is handled through driver model

8.  * probe()/remove() methods.  A driver may be bound to this device when we

9.  * return from this function, or any later moment (e.g. maybe hotplugging will

10.  * load the driver module).  This call is not appropriate for use by mainboard

11.  * initialization logic, which usually runs during an arch_initcall() long

12.  * before any i2c_adapter could exist.

13.  *

14.  * This returns the new i2c client, which may be saved for later use with

15.  * i2c_unregister_device(); or NULL to indicate an error.

16.  */

17. struct i2c_client *

18. i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

19. {

20.     struct i2c_client   *client;

21.     int         status;

22. 

23.     client = kzalloc(sizeof *client, GFP_KERNEL);

24.     if (!client)

25.         return NULL;

26. 

27.     client->adapter = adap;

28. 

29.     client->dev.platform_data = info->platform_data;

30. 

31.     if (info->archdata)

32.         client->dev.archdata = *info->archdata;

33. 

34.     client->flags = info->flags;

35.     client->addr = info->addr;

36.     client->irq = info->irq;

37. 

38.     strlcpy(client->name, info->type, sizeof(client->name));

39. 

40.     /* Check for address validity */

41.     status = i2c_check_client_addr_validity(client);

42.     if (status) {

43.         dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",

44.             client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);

45.         goto out_err_silent;

46.     }

47. 

48.     /* Check for address business */

49.     status = i2c_check_addr_busy(adap, client->addr);

50.     if (status)

51.         goto out_err;

52. 

53.     client->dev.parent = &client->adapter->dev;

54.     client->dev.bus = &i2c_bus_type;

55.     client->dev.type = &i2c_client_type;

56.     client->dev.of_node = info->of_node;

57. 

58.     dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),

59.              client->addr);

60.     status = device_register(&client->dev);

61.     if (status)

62.         goto out_err;

63. 

64.     dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",

65.         client->name, dev_name(&client->dev));

66. 

67.     return client;

68. 

69. out_err:

70.     dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "

71.         "(%d)\n", client->name, client->addr, status);

72. out_err_silent:

73.     kfree(client);

74.     return NULL;

75. }

76. EXPORT_SYMBOL_GPL(i2c_new_device);

77. 

78. 代碼清單14 i2c_unregister_device函數

79. /**

80.  * i2c_unregister_device - reverse effect of i2c_new_device()

81.  * @client: value returned from i2c_new_device()

82.  * Context: can sleep

83.  */

84. void i2c_unregister_device(struct i2c_client *client)

85. {

86.     device_unregister(&client->dev);

87. }

88. EXPORT_SYMBOL_GPL(i2c_unregister_device);

5.I2C傳輸、發送和接收

I2c_transfer()函數本身不具備驅動適配器物理硬件完成消息交互的能力,它只是尋找到i2c_adapter對應的i2c_algorithm,並使用i2c_algorithmmaster_xfer()函數真正驅動硬件流程。

代碼清單15 i2c_transfer函數

1. /* ----------------------------------------------------

2.  * the functional interface to the i2c busses.

3.  * ----------------------------------------------------

4.  */

5. 

6. /**

7.  * i2c_transfer - execute a single or combined I2C message

8.  * @adap: Handle to I2C bus

9.  * @msgs: One or more messages to execute before STOP is issued to

10.  *  terminate the operation; each message begins with a START.

11.  * @num: Number of messages to be executed.

12.  *

13.  * Returns negative errno, else the number of messages executed.

14.  *

15.  * Note that there is no requirement that each message be sent to

16.  * the same slave address, although that is the most common model.

17.  */

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

19. {

20.     unsigned long orig_jiffies;

21.     int ret, try;

22. 

23.     /* REVISIT the fault reporting model here is weak:

24.      *

25.      *  - When we get an error after receiving N bytes from a slave,

26.      *    there is no way to report "N".

27.      *

28.      *  - When we get a NAK after transmitting N bytes to a slave,

29.      *    there is no way to report "N" ... or to let the master

30.      *    continue executing the rest of this combined message, if

31.      *    that's the appropriate response.

32.      *

33.      *  - When for example "num" is two and we successfully complete

34.      *    the first message but get an error part way through the

35.      *    second, it's unclear whether that should be reported as

36.      *    one (discarding status on the second message) or errno

37.      *    (discarding status on the first one).

38.      */

39. 

40.     if (adap->algo->master_xfer) {

41. #ifdef DEBUG

42.         for (ret = 0; ret < num; ret++) {

43.             dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "

44.                 "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)

45.                 ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,

46.                 (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");

47.         }

48. #endif

49. 

50.         if (in_atomic() || irqs_disabled()) {

51.             ret = i2c_trylock_adapter(adap);

52.             if (!ret)

53.                 /* I2C activity is ongoing. */

54.                 return -EAGAIN;

55.         } else {

56.             i2c_lock_adapter(adap);

57.         }

58. 

59.         /* Retry automatically on arbitration loss */

60.         orig_jiffies = jiffies;

61.         for (ret = 0, try = 0; try <= adap->retries; try++) {

62.             ret = adap->algo->master_xfer(adap, msgs, num);

63.             if (ret != -EAGAIN)

64.                 break;

65.             if (time_after(jiffies, orig_jiffies + adap->timeout))

66.                 break;

67.         }

68.         i2c_unlock_adapter(adap);

69. 

70.         return ret;

71.     } else {

72.         dev_dbg(&adap->dev, "I2C level transfers not supported\n");

73.         return -EOPNOTSUPP;

74.     }

75. }

76. EXPORT_SYMBOL(i2c_transfer);

代碼清單16 i2c_master_send函數

1. /**

2.  * i2c_master_send - issue a single I2C message in master transmit mode

3.  * @client: Handle to slave device

4.  * @buf: Data that will be written to the slave

5.  * @count: How many bytes to write, must be less than 64k since msg.len is u16

6.  *

7.  * Returns negative errno, or else the number of bytes written.

8.  */

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

10. {

11.     int ret;

12.     struct i2c_adapter *adap = client->adapter;

13.     struct i2c_msg msg;

14. 

15.     msg.addr = client->addr;

16.     msg.flags = client->flags & I2C_M_TEN;

17.     msg.len = count;

18.     msg.buf = (char *)buf;

19. 

20.     ret = i2c_transfer(adap, &msg, 1);

21. 

22.     /* If everything went ok (i.e. 1 msg transmitted), return #bytes

23.        transmitted, else error code. */

24.     return (ret == 1) ? count : ret;

25. }

26. EXPORT_SYMBOL(i2c_master_send);

代碼清單17 i2c_master_recv函數

1. /**

2.  * i2c_master_recv - issue a single I2C message in master receive mode

3.  * @client: Handle to slave device

4.  * @buf: Where to store data read from slave

5.  * @count: How many bytes to read, must be less than 64k since msg.len is u16

6.  *

7.  * Returns negative errno, or else the number of bytes read.

8.  */

9. int i2c_master_recv(const struct i2c_client *client, char *buf, int count)

10. {

11.     struct i2c_adapter *adap = client->adapter;

12.     struct i2c_msg msg;

13.     int ret;

14. 

15.     msg.addr = client->addr;

16.     msg.flags = client->flags & I2C_M_TEN;

17.     msg.flags |= I2C_M_RD;

18.     msg.len = count;

19.     msg.buf = buf;

20. 

21.     ret = i2c_transfer(adap, &msg, 1);

22. 

23.     /* If everything went ok (i.e. 1 msg transmitted), return #bytes

24.        transmitted, else error code. */

25.     return (ret == 1) ? count : ret;

26. }

27. EXPORT_SYMBOL(i2c_master_recv);

i2c_transfer()函數用於進行I2C適配器和I2C設備之間的一組消息交互,i2c_master_send()函數和i2c_master_recv()函數內部會調用i2c_transfer函數分別完成一條寫消息和一條讀消息。

三、I2c的第二部分
1.2C總線驅動

(1)I2c總線驅動模塊的加載函數要完成兩個工作。

l 第一個是初始化i2c適配器所使用的硬件資源,如申請I/O地址、中斷號等。

l 第二個是通過i2c_add_adapter()添加i2c_adapter的數據結構,當然這個i2c_adapter數據結構的成員已經被xxx適配器的相應的函數指針所初始化。

(2)I2C總線驅動模塊的卸載函數要完成的工作與加載函數相反。

l 釋放I2C適配器所使用的硬件資源,如釋放I/O地址,中斷號等。

l 通過i2c_del_adapter()刪除i2c_adapter的函數數據結構。

代碼清單18所示爲I2C適配器驅動的模塊加載和卸載函數的模板。

代碼清單18 I2C總線驅動的模板加載和卸載函數模板

1. static int __init i2c_adap_xxx_init(void)

2. {

3.     xxx_adapter_hw_init();

4.     I2c_add_adapter(&xxx_adapter)

5. }

6. subsys_initcall(i2c_adap_xxx_init);

7. 

8. static void __exit i2c_adap_xxx_exit(void)

9. {

10.     xxx_adapter_hw_free();

11.     i2c_del_adapter(&xxx_adapter);

12. }

13. module_exit(i2c_adap_xxx_exit);

上述代碼中xxx_adapter_hw_init()xxx_adapter_hw_free()函數的實現都與具體的CPUI2C適配器硬件直接相關。

2.I2C總線通信方法

我們需要爲特定的I2C適配器實現其通信方法,主要實現i2c_algorithmmaster_xfer()函數和functionality()函數。

Functionality()函數非常簡單,用於返回algorithm所支持的通信協議,如I2C_FUNC_I2CI2C_FUNC_10BIT_ADDRI2C_FUNC_SMBUS_READ_BYTEI2C_FUNC_SUMBUS_WRITE_BYTE等。

Master_xfer()函數在I2C適配器上完成傳遞給它的i2c_msg數組中每個I2C消息,代碼清單19所示爲xxx設備的master_xfer()函數模板。

代碼清單19 I2C總線驅動master_xfer()函數模板

1. static int i2c_adapter_xxx_xfer(structi2c_adapter *adap, struct i2c_msg *msgs, int num) 

2. { 

3. ...... 

4. for (i = 0; i < num; i++) { 

5. i2c_adapter_xxx_start(); /*產生起始位*/ 

6. if (msgs[i]->flags & I2C_M_RD) { /*讀取*/ 

7. i2c_adapter_xxx_setaddr((msg->addr << 1) | 1); /*發送從設備地址*/ 

8. i2c_adapter_xxx_wait_ack(); /*獲得從設備的ACK*/ 

9. i2c_adapter_xxx_readbytes(msgs[i]->buf,msgs[i]->len); /*讀取len長度的數據到buf*/ 

10. } else { 

11. i2c_adapter_xxx_setaddr(msg->addr << 1); 

12. i2c_adapter_xxx_wait_ack(); 

13. i2c_adapter_xxx_writebytes(msgs[i]->buf, msgs[i]->len); 

14. } 

15. } 

16. i2c_adapter_xxx_stop(); /*產生停止位*/ 

17. } 

上述代碼實際上給出了一個master_xfer()函數處理I2C消息數組的流程,對於數組中的每個消息,判斷消息類型,若爲讀消息,則賦從設備地址爲(msg->addr<<1|1,否則爲msg->addr<<1,對每個消息產生一個開始位,緊接着傳送從設備的地址,然後開始數據的發送或接收,隊最後的消息還需產生一個停止位。

master_xfer()函數模板中i2c_adapter_xxx_start()i2c_adapter_xxx_setaddr()i2c_adapter_xxx_wait_ack()i2c_adapter_xxx_readbytes()i2c_adapter_xxx_stop()函數用於完成適配器底層硬件操作,與I2C適配器和CPU的具體硬件直接相關,需要由工程師根據芯片的數據手冊來實現。

I2c_adapter_xxx_readbytes()用於從設備上接收一串數據,i2c_adapter_xxx_writebytes()用於向從設備寫入一串數據,這兩個函數的內部也會涉及I2C總線協議中的ACK應答。

master_xfer()函數的實現在形式上會有很多樣,即便是linux內核源代碼中已經給出了一些I2C總線驅動的master_xfer()函數,由於由不同的組織或個人完成,風格上的差別也非常大,不一定能與模板完全對應,如master_xfer()函數模板給出的消息處理順序進行的,而有的驅動以中斷方式來完成這個流程。不管具體怎麼實施,流程的本質都是不變的。因爲這個流程不以驅動工程師的意志爲轉移,最終由I2C總線硬件上的通信協議決定。

多數I2C總線驅動會定義一個xxx_i2c結構體,作爲i2c_adapteralgo_data(類似“是有數據”),其中包含I2C消息數組指針、數組索引及I2C適配器algorithm訪問控制用的自旋鎖、等待隊列等,而master_xfer()函數完成消息數組中消息的處理也可通過對xxx_i2c結構體相關成員的訪問來控制。代碼清單20所示爲xxx_i2c結構體的定義

代碼清單20 xxx_i2c結構體模板

1. struct xxx_i2c {

2.     spinlock_t          lock;

3.     wait_queue_head_t   wait;

4.     struct i2c_msg      *msg;

5.     unsigned int        msg_num;

6.     unsigned int        msg_idx;

7.     unsigned int        msg_ptr;

8.     struct i2c_adapter  adap;

9. };

對於s3c2440i2c模塊而言內核中做了如下的工作:

S3c2440處理器內部集成了一個I2C控制器,通過4個寄存器就可以方便地對其進行控制,這4個寄存器如下:

l IICCONI2C控制寄存器。

l IICSTAT:I2C狀態寄存器。

l IICDSI2C收發數據移位寄存器。

l IICADDI2C地址寄存器。

S3c2440處理器內部集成的I2C控制器可支持主、從兩種模式,我們主要使用其主模式。通過對IICCONIICDSIICADD寄存器的操作,可

I2C總線上產生開始位、停止位、數據和地址,而傳輸的狀態則通過IICSTAT寄存器獲取。

3.s3c2440 I2C 總線驅動總體分析

s3c_2440I2C總線驅動driver/i2c/busses/i2c-s3c2410.c支持s3c24xxs3c64xxs5pc1xxs5p64xx處理器,在我們使用的3.0內核版本中,其名稱任然叫2410,顯然是歷史原因引起的。它主要完成以下工作。

設計對應於i2c_adapter_xxx_init()模板的s3c_2440的模塊加載函數和對應於i2c_adapter_xxx_exit()函數模板的模塊卸載函數。

設計對應於i2c_adapter_xxx_xfer()模板的s3c_2440適配器的通信方法函數。

針對s3c24xxs3c64xxs5pc1xxs5p64xx處理器,functionality()函數s3c24xx_i2c_func()只需要簡單地返回I2C_FUNC_I2C|I2C_FUNC_SUMBUS_EMUL|I2C_FUNU_PROTOCOL_MANGLING表明其支持的功能。

下圖給出了s3c2440驅動中的主要函數與總線模板函數的對應關係,由於實現通信方法的方式不一樣,模板的一個函數可能對應於s3c2440 I2C總線驅動的多個函數。

6 i2c總線驅動模板於s3c2440 I2C總線驅動的映射

4.S3c2440 I2C適配器驅動的模板加載於卸載

I2C適配器驅動被作爲一個單獨的模塊加載進內核,在模塊的加載和卸載函數中,只需註冊和註銷一個platform——driver結構體,如代碼清單21所示。

代碼清單21 S3c2440 I2C

1. static int __init i2c_adap_s3c_init(void)

2. {

3.     return platform_driver_register(&s3c24xx_i2c_driver);

4. }

5. subsys_initcall(i2c_adap_s3c_init);

6. 

7. static void __exit i2c_adap_s3c_exit(void)

8. {

9.     platform_driver_unregister(&s3c24xx_i2c_driver);

10. }

11. module_exit(i2c_adap_s3c_exit);

代碼清單22 platfrom_driver_register()platfrom_driver_unregister()函數

1. /**

2.  * platform_driver_register - register a driver for platform-level devices

3.  * @drv: platform driver structure

4.  */

5. int platform_driver_register(struct platform_driver *drv)

6. {

7.     drv->driver.bus = &platform_bus_type;

8.     if (drv->probe)

9.         drv->driver.probe = platform_drv_probe;

10.     if (drv->remove)

11.         drv->driver.remove = platform_drv_remove;

12.     if (drv->shutdown)

13.         drv->driver.shutdown = platform_drv_shutdown;

14. 

15.     return driver_register(&drv->driver);

16. }

17. EXPORT_SYMBOL_GPL(platform_driver_register);

18. 

19. /**     

20.  * platform_driver_unregister - unregister a driver for platform-level devices

21.  * @drv: platform driver structure

22.  */

23. void platform_driver_unregister(struct platform_driver *drv)

24. {   

25.     driver_unregister(&drv->driver);

26. }   

27. EXPORT_SYMBOL_GPL(platform_driver_unregister);

Platfrom_driver結構體包含了具體適配器的probe()函數、remove()函數、resume()函數指針等信息,它需要被定義和賦值,如代碼清單23所示。

代碼清單23 platfrom_driver結構體

1. static struct platform_driver s3c24xx_i2c_driver = {

2.     .probe      = s3c24xx_i2c_probe,

3.     .remove     = s3c24xx_i2c_remove,

4.     .id_table   = s3c24xx_driver_ids,

5.     .driver     = {

6.         .owner  = THIS_MODULE,

7.         .name   = "s3c-i2c",

8.         .pm = S3C24XX_DEV_PM_OPS,

9.     },

10. };

當通過linux內核源代碼/drivers/base/platform.c文件中定義platform_driver_register()函數註冊platfrom_driver結構體時,其中probe指針指向s3c24xx_i2c_probe()函數將被調用,以初始化適配器硬件。s3c24xx_i2c_init()函數會調用函數。

代碼清單24 s3c24xx_i2c_init()函數

1. /* s3c24xx_i2c_init

2.  *

3.  * initialise the controller, set the IO lines and frequency

4. */

5. 

6. static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)

7. {

8.     unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;

9.     struct s3c2410_platform_i2c *pdata;

10.     unsigned int freq;

11. 

12.     /* get the plafrom data */

13. 

14.     pdata = i2c->dev->platform_data;

15. 

16.     /* inititalise the gpio */

17. 

18.     if (pdata->cfg_gpio)

19.         pdata->cfg_gpio(to_platform_device(i2c->dev));

20. 

21.     /* write slave address */

22. 

23.     writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);

24. 

25.     dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);

26. 

27.     writel(iicon, i2c->regs + S3C2410_IICCON);

28. 

29.     /* we need to work out the divisors for the clock... */

30. 

31.     if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {

32.         writel(0, i2c->regs + S3C2410_IICCON);

33.         dev_err(i2c->dev, "cannot meet bus frequency required\n");

34.         return -EINVAL;

35.     }

36. 

37.     /* todo - check that the i2c lines aren't being dragged anywhere */

38. 

39.     dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);

40.     dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);

41. 

42.     return 0;

43. }

44. 

代碼清單25 s3c24xx_i2c_probe()函數

1. /* s3c24xx_i2c_probe

2.  *

3.  * called by the bus driver when a suitable device is found

4. */

5. 

6. static int s3c24xx_i2c_probe(struct platform_device *pdev)

7. {

8.     struct s3c24xx_i2c *i2c;

9.     struct s3c2410_platform_i2c *pdata;

10.     struct resource *res;

11.     int ret;

12. 

13.     pdata = pdev->dev.platform_data;

14.     if (!pdata) {

15.         dev_err(&pdev->dev, "no platform data\n");

16.         return -EINVAL;

17.     }

18. 

19.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);

20.     if (!i2c) {

21.         dev_err(&pdev->dev, "no memory for state\n");

22.         return -ENOMEM;

23.     }

24. 

25.     strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));

26.     i2c->adap.owner   = THIS_MODULE;

27.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;

28.     i2c->adap.retries = 2;

29.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;

30.     i2c->tx_setup     = 50;

31. 

32.     spin_lock_init(&i2c->lock);

33.     init_waitqueue_head(&i2c->wait);

34. 

35.     /* find the clock and enable it */

36. 

37.     i2c->dev = &pdev->dev;

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

39.     if (IS_ERR(i2c->clk)) {

40.         dev_err(&pdev->dev, "cannot get clock\n");

41.         ret = -ENOENT;

42.         goto err_noclk;

43.     }

44. 

45.     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);

46. 

47.     clk_enable(i2c->clk);

48. 

49.     /* map the registers */

50. 

51.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

52.     if (res == NULL) {

53.         dev_err(&pdev->dev, "cannot find IO resource\n");

54.         ret = -ENOENT;

55.         goto err_clk;

56.     }

57. 

58.     i2c->ioarea = request_mem_region(res->start, resource_size(res),

59.                      pdev->name);

60. 

61.     if (i2c->ioarea == NULL) {

62.         dev_err(&pdev->dev, "cannot request IO\n");

63.         ret = -ENXIO;

64.         goto err_clk;

65.     }

66. 

67.     i2c->regs = ioremap(res->start, resource_size(res));

68. 

69.     if (i2c->regs == NULL) {

70.         dev_err(&pdev->dev, "cannot map IO\n");

71.         ret = -ENXIO;

72.         goto err_ioarea;

73.     }

74. 

75.     dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",

76.         i2c->regs, i2c->ioarea, res);

77. 

78.     /* setup info block for the i2c core */

79. 

80.     i2c->adap.algo_data = i2c;

81.     i2c->adap.dev.parent = &pdev->dev;

82. 

83.     /* initialise the i2c controller */

84. 

85.     ret = s3c24xx_i2c_init(i2c);

86.     if (ret != 0)

87.         goto err_iomap;

88. 

89.     /* find the IRQ for this unit (note, this relies on the init call to

90.      * ensure no current IRQs pending

91.      */

92. 

93.     i2c->irq = ret = platform_get_irq(pdev, 0);

94.     if (ret <= 0) {

95.         dev_err(&pdev->dev, "cannot find IRQ\n");

96.         goto err_iomap;

97.     }

98. 

99.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,

100.               dev_name(&pdev->dev), i2c);

101. 

102.     if (ret != 0) {

103.         dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);

104.         goto err_iomap;

105.     }

106. 

107.     ret = s3c24xx_i2c_register_cpufreq(i2c);

108.     if (ret < 0) {

109.         dev_err(&pdev->dev, "failed to register cpufreq notifier\n");

110.         goto err_irq;

111.     }

112. 

113.     /* Note, previous versions of the driver used i2c_add_adapter()

114.      * to add the bus at any number. We now pass the bus number via

115.      * the platform data, so if unset it will now default to always

116.      * being bus 0.

117.      */

118. 

119.     i2c->adap.nr = pdata->bus_num;

120. 

121.     ret = i2c_add_numbered_adapter(&i2c->adap);

122.     if (ret < 0) {

123.         dev_err(&pdev->dev, "failed to add bus to i2c core\n");

124.         goto err_cpufreq;

125.     }

126. 

127.     platform_set_drvdata(pdev, i2c);

128. 

129.     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));

130.     clk_disable(i2c->clk);

131.     return 0;

132. 

133.  err_cpufreq:

134.     s3c24xx_i2c_deregister_cpufreq(i2c);

135. 

136.  err_irq:

137.     free_irq(i2c->irq, i2c);

138. 

139.  err_iomap:

140.     iounmap(i2c->regs);

141. 

142.  err_ioarea:

143.     release_resource(i2c->ioarea);

144.     kfree(i2c->ioarea);

145. 

146.  err_clk:

147.     clk_disable(i2c->clk);

148.     clk_put(i2c->clk);

149. 

150.  err_noclk:

151.     kfree(i2c);

152.     return ret;

153. }

上述代碼中的主體工作是使能硬件並且申請I2C適配器使用I/O地址、中斷號等,在這些工作都完成無誤後,通過I2C核心提供i2c_add_adapter函數添加這個適配器。當處理器包含多個I2C控制器時,我們通過板文件定義的platform數據中bus_num進行區分。

s3c24xx_i2c_probe()函數完全相反的功能的函數是s3c24xx_i2c_remove()函數,它在適配器模塊函數調用platform_driver_unregister函數是通過platfrom_driverremove指針方式被調用。Xxx_i2c_remove()的設計模塊如代碼清單26所示。

 

********************************************************************************************

轉載聲明:希望大家能轉載此文謝謝  原文鏈接

********************************************************************************************

 

代碼清單26 s3c2440 I2C總線驅動中的s3c24xx_i2c_remove函數

1. /* s3c24xx_i2c_remove

2.  *

3.  * called when device is removed from the bus

4. */

5. 

6. static int s3c24xx_i2c_remove(struct platform_device *pdev)

7. {

8.     struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);

9. 

10.     s3c24xx_i2c_deregister_cpufreq(i2c);

11. 

12.     i2c_del_adapter(&i2c->adap);

13.     free_irq(i2c->irq, i2c);

14. 

15.     clk_disable(i2c->clk);

16.     clk_put(i2c->clk);

17. 

18.     iounmap(i2c->regs);

19. 

20.     release_resource(i2c->ioarea);

21.     kfree(i2c->ioarea);

22.     kfree(i2c);

23. 

24.     return 0;

25. }

上面的代碼清單26中用到了s3c24xx_i2c結構體進行適配器所有信息的封裝。類似於私有信息結構體,它與代碼清單20所示的xxx_i2c結構體模板對應,代碼清單27所示爲s3c24xx_i2c結構體的定義。

代碼清單27 s3c24xx_i2c結構體

1. struct s3c24xx_i2c {

2.     spinlock_t      lock;

3.     wait_queue_head_t   wait;

4.     unsigned int        suspended:1;

5. 

6.     struct i2c_msg      *msg;

7.     unsigned int        msg_num;

8.     unsigned int        msg_idx;

9.     unsigned int        msg_ptr;

10. 

11.     unsigned int        tx_setup;

12.     unsigned int        irq;

13. 

14.     enum s3c24xx_i2c_state  state;

15.     unsigned long       clkrate;

16. 

17.     void __iomem        *regs;

18.     struct clk      *clk;

19.     struct device       *dev;

20.     struct resource     *ioarea;

21.     struct i2c_adapter  adap;

22. 

23. #ifdef CONFIG_CPU_FREQ

24.     struct notifier_block   freq_transition;

25. #endif

26. };

5.s3c2440 I2C 總線通信方法

由代碼清單2523行可以看出,I2C適配器對應的i2c_algorithm結構體實例爲s3c24xx_i2c_algorithm,代碼清單28所示爲s3c24xx_i2c_algorithm的定義。

代碼清單28 s3c2440i2c_algorithm結構體

1. /* i2c bus registration info */

2. 

3. static const struct i2c_algorithm s3c24xx_i2c_algorithm = {

4.     .master_xfer        = s3c24xx_i2c_xfer,

5.     .functionality      = s3c24xx_i2c_func,

6. };

上述代碼第一行指定了s3c2440 I2C總線通信傳輸函數s3c24xx_i2c_xfer(),這個函數非常關鍵,所有I2C總線上對設備的訪問最終應該由它來完成,代碼清單29所示爲這個重要函數以及其依賴的s3c24xx_i2c_doxfer()函數和s3c24xx_i2c_message_start()函數的源代碼。

代碼清單29 s3c2440 I2C總線驅動的master_xfer函數

1. /* s3c24xx_i2c_xfer

2.  *

3.  * first port of call from the i2c bus code when an message needs

4.  * transferring across the i2c bus.

5. */

6. 

7. static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,

8.             struct i2c_msg *msgs, int num)

9. {

10.     struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;

11.     int retry;

12.     int ret;

13. 

14.     clk_enable(i2c->clk);

15. 

16.     for (retry = 0; retry < adap->retries; retry++) {

17. 

18.         ret = s3c24xx_i2c_doxfer(i2c, msgs, num);

19. 

20.         if (ret != -EAGAIN) {

21.             clk_disable(i2c->clk);

22.             return ret;

23.         }

24. 

25.         dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);

26. 

27.         udelay(100);

28.     }

29. 

30.     clk_disable(i2c->clk);

31.     return -EREMOTEIO;

32. }

s3c24xx_i2c_xfer()函數調用s3c24xx_i2c_doxfer()函數傳輸I2C消息,第13行的循環意味着最多可以重試adap->retres次。

代碼清單30 s3c24xx_i2c_doxfer()函數

1. /* s3c24xx_i2c_doxfer

2.  *

3.  * this starts an i2c transfer

4. */

5. 

6. static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,

7.                   struct i2c_msg *msgs, int num)

8. {

9.     unsigned long iicstat, timeout;

10.     int spins = 20;

11.     int ret;

12. 

13.     if (i2c->suspended)

14.         return -EIO;

15. 

16.     ret = s3c24xx_i2c_set_master(i2c);

17.     if (ret != 0) {

18.         dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);

19.         ret = -EAGAIN;

20.         goto out;

21.     }

22. 

23.     spin_lock_irq(&i2c->lock);

24. 

25.     i2c->msg     = msgs;

26.     i2c->msg_num = num;

27.     i2c->msg_ptr = 0;

28.     i2c->msg_idx = 0;

29.     i2c->state   = STATE_START;

30. 

31.     s3c24xx_i2c_enable_irq(i2c);

32.     s3c24xx_i2c_message_start(i2c, msgs);

33.     spin_unlock_irq(&i2c->lock);

34. 

35.     timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);

36. 

37.     ret = i2c->msg_idx;

38. 

39.     /* having these next two as dev_err() makes life very

40.      * noisy when doing an i2cdetect */

41. 

42.     if (timeout == 0)

43.         dev_dbg(i2c->dev, "timeout\n");

44.     else if (ret != num)

45.         dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);

46. 

47.     /* ensure the stop has been through the bus */

48. 

49.     dev_dbg(i2c->dev, "waiting for bus idle\n");

50. 

51.     /* first, try busy waiting briefly */

52.     do {

53.         iicstat = readl(i2c->regs + S3C2410_IICSTAT);

54. } while ((iicstat & S3C2410_IICSTAT_START) && --spins);

55. 

56.     /* if that timed out sleep */

57.     if (!spins) {

58.         msleep(1);

59.         iicstat = readl(i2c->regs + S3C2410_IICSTAT);

60.     }

61. 

62.     if (iicstat & S3C2410_IICSTAT_START)

63.         dev_warn(i2c->dev, "timeout waiting for bus idle\n");

64. 

65.  out:

66.     return ret;

67. }

s3c24xx_i2c_doxfer()首先將s3c2440I2C適配器設置爲I2C主設備,其後初始化s3c24xx_i2c結構體,使能I2C中斷,並調用s3c24xx_i2c_message_start()函數啓動I2C消息的傳輸。

代碼清單31 s3c24xx_i2c_message_start()函數

1. /* s3c24xx_i2c_message_start

2.  *

3.  * put the start of a message onto the bus

4. */

5. 

6. static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,

7.                       struct i2c_msg *msg)

8. {

9.     unsigned int addr = (msg->addr & 0x7f) << 1;

10.     unsigned long stat;

11.     unsigned long iiccon;

12. 

13.     stat = 0;

14.     stat |=  S3C2410_IICSTAT_TXRXEN;

15. 

16.     if (msg->flags & I2C_M_RD) {

17.         stat |= S3C2410_IICSTAT_MASTER_RX;

18.         addr |= 1;

19.     } else

20.         stat |= S3C2410_IICSTAT_MASTER_TX;

21. 

22.     if (msg->flags & I2C_M_REV_DIR_ADDR)

23.         addr ^= 1;

24. 

25.     /* todo - check for wether ack wanted or not */

26.     s3c24xx_i2c_enable_ack(i2c);

27. 

28.     iiccon = readl(i2c->regs + S3C2410_IICCON);

29.     writel(stat, i2c->regs + S3C2410_IICSTAT);

30. 

31.     dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);

32.     writeb(addr, i2c->regs + S3C2410_IICDS);

33. 

34.     /* delay here to ensure the data byte has gotten onto the bus

35.      * before the transaction is started */

36. 

37.     ndelay(i2c->tx_setup);

38.     dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);

39.     writel(iiccon, i2c->regs + S3C2410_IICCON);

40. 

41.     stat |= S3C2410_IICSTAT_START;

42.     writel(stat, i2c->regs + S3C2410_IICSTAT);

43. }

s3c24xx_i2c_message_start()函數寫s3c2440適配器對應的控制寄存器,向I2C從設備傳遞開始位和從設備地址。

上述代碼只是啓動了I2C消息數組的傳輸週期,並沒有完整實現algorithm master_xfer時序的流程。這個流程的完整實現需要藉助I2C適配器上的中斷來步步推進。代碼清單32所示爲s3c2440 I2C適配器中斷處理函數以及其依賴的i2c_s3c_irq_nextbyte()函數的源碼。

代碼清單32 s3c2440 I2C適配器中斷處理函數

1. /* i2c_s3c_irq_nextbyte

2.  *

3.  * process an interrupt and work out what to do

4.  */

5. 

6. static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)

7. {

8.     unsigned long tmp;

9.     unsigned char byte;

10.     int ret = 0;

11. 

12.     switch (i2c->state) {

13. 

14.     case STATE_IDLE:

15.         dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);

16.         goto out;

17. 

18.     case STATE_STOP:

19.         dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);

20.         s3c24xx_i2c_disable_irq(i2c);

21.         goto out_ack;

22. 

23.     case STATE_START:

24.         /* last thing we did was send a start condition on the

25.          * bus, or started a new i2c message

26.          */

27. 

28.         if (iicstat & S3C2410_IICSTAT_LASTBIT &&

29.             !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {

30.             /* ack was not received... */

31. 

32.             dev_dbg(i2c->dev, "ack was not received\n");

33.             s3c24xx_i2c_stop(i2c, -ENXIO);

34.             goto out_ack;

35.         }

36. 

37.         if (i2c->msg->flags & I2C_M_RD)

38.             i2c->state = STATE_READ;

39.         else

40.             i2c->state = STATE_WRITE;

41. 

42.         /* terminate the transfer if there is nothing to do

43.          * as this is used by the i2c probe to find devices. */

44. 

45.         if (is_lastmsg(i2c) && i2c->msg->len == 0) {

46.             s3c24xx_i2c_stop(i2c, 0);

47.             goto out_ack;

48.         }

49. 

50.         if (i2c->state == STATE_READ)

51.             goto prepare_read;

52. 

53.         /* fall through to the write state, as we will need to

54.          * send a byte as well */

55. 

56.     case STATE_WRITE:

57.         /* we are writing data to the device... check for the

58.          * end of the message, and if so, work out what to do

59.          */

60. 

61.         if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {

62.             if (iicstat & S3C2410_IICSTAT_LASTBIT) {

63.                 dev_dbg(i2c->dev, "WRITE: No Ack\n");

64. 

65.                 s3c24xx_i2c_stop(i2c, -ECONNREFUSED);

66.                 goto out_ack;

67.             }

68.         }

69. 

70.  retry_write:

71. 

72.         if (!is_msgend(i2c)) {

73.             byte = i2c->msg->buf[i2c->msg_ptr++];

74.             writeb(byte, i2c->regs + S3C2410_IICDS);

75. 

76.             /* delay after writing the byte to allow the

77.              * data setup time on the bus, as writing the

78.              * data to the register causes the first bit

79.              * to appear on SDA, and SCL will change as

80.              * soon as the interrupt is acknowledged */

81. 

82.             ndelay(i2c->tx_setup);

83. 

84.         } else if (!is_lastmsg(i2c)) {

85.             /* we need to go to the next i2c message */

86. 

87.             dev_dbg(i2c->dev, "WRITE: Next Message\n");

88. 

89.             i2c->msg_ptr = 0;

90.             i2c->msg_idx++;

91.             i2c->msg++;

92. 

93.             /* check to see if we need to do another message */

94.             if (i2c->msg->flags & I2C_M_NOSTART) {

95. 

96.                 if (i2c->msg->flags & I2C_M_RD) {

97.                     /* cannot do this, the controller

98.                      * forces us to send a new START

99.                      * when we change direction */

100. 

101.                     s3c24xx_i2c_stop(i2c, -EINVAL);

102.                 }

103. 

104.                 goto retry_write;

105.             } else {

106.                 /* send the new start */

107.                 s3c24xx_i2c_message_start(i2c, i2c->msg);

108.                 i2c->state = STATE_START;

109.             }

110. 

111.         } else {

112.             /* send stop */

113. 

114.             s3c24xx_i2c_stop(i2c, 0);

115.         }

116.         break;

117. 

118.     case STATE_READ:

119.         /* we have a byte of data in the data register, do

120.          * something with it, and then work out wether we are

121.          * going to do any more read/write

122.          */

123. 

124.         byte = readb(i2c->regs + S3C2410_IICDS);

125.         i2c->msg->buf[i2c->msg_ptr++] = byte;

126. 

127.  prepare_read:

128.         if (is_msglast(i2c)) {

129.             /* last byte of buffer */

130. 

131.             if (is_lastmsg(i2c))

132.                 s3c24xx_i2c_disable_ack(i2c);

133. 

134.         } else if (is_msgend(i2c)) {

135.             /* ok, we've read the entire buffer, see if there

136.              * is anything else we need to do */

137. 

138.             if (is_lastmsg(i2c)) {

139.                 /* last message, send stop and complete */

140.                 dev_dbg(i2c->dev, "READ: Send Stop\n");

141. 

142.                 s3c24xx_i2c_stop(i2c, 0);

143.             } else {

144.                 /* go to the next transfer */

145.                 dev_dbg(i2c->dev, "READ: Next Transfer\n");

146. 

147.                 i2c->msg_ptr = 0;

148.                 i2c->msg_idx++;

149.                 i2c->msg++;

150.             }

151.         }

152. 

153.         break;

154.     }

155. 

156.     /* acknowlegde the IRQ and get back on with the work */

157. 

158.  out_ack:

159.     tmp = readl(i2c->regs + S3C2410_IICCON);

160.     tmp &= ~S3C2410_IICCON_IRQPEND;

161.     writel(tmp, i2c->regs + S3C2410_IICCON);

162.  out:

163.     return ret;

164. }

中斷處理函數s3c24xx_i2c_irq()主要通過調用i2c_s3c_irq_nextbyte()函數進行傳輸工作的進一步推進。I2c_s3c_irq_nextbyte()函數通過switchi2c->state)的不同狀態進行處理,在每種狀態下,先檢查i2c->state的狀態與硬件寄存器應該處於的狀態是否一致,如果不一致,則證明有誤,直接返回。當I2C處於讀狀態STATE_READ或是寫狀態STATE_WRITE時,通過is_lastmsg()函數判斷是否傳輸的最後一條I2C消息,如果是,則產生停止位,否則通過i2c->msg_idx++i2c->msg++推進到下一條消息。

四、I2C的第三部分
1.Linux I2C 設備驅動

I2C設備驅動要使用i2c_driveri2c_client數據結構並填充i2c_driver中的成員函數。I2c_client一般被包含在設備的私有信息結構體yyy_data中,而i2c_driver則適合被定義爲全局變量並初始化,代碼清單33所示爲已被初始化的i2c_driver

代碼清單33 已被初始化的i2c_driver

1. static struct i2c_driver yyy_driver= {

2. .driver = {

3. .name = “yyy”,

4. },

5. .probe = yyy_probe,

6. .remove = yyy_remove,

7. .id_table = yyy_id,

8. };

2.Linux I2C 設備驅動的模塊加載與卸載

I2C設備驅動的模塊加載函數通用的方法是在I2C設備驅動模塊加載函數進行通過I2C核心的i2c_add_driver()函數添加i2c_driver的工作,而在模塊卸載函數中需要做相反的工作:通過I2C核心的i2c_del_driver()函數刪除i2c_driver。代碼清單34所示爲I2C設備驅動的加載與卸載函數模板

代碼清單34 I2C設備驅動的加載與卸載函數模板

1. Static int __init yyy_init(void)

2. {

3. return i2c_add_driver(&yyy_driver);

4. };

5. void __exit yyy_exit(void)

6. {

7. i2c_del_driver(&yyy_driver);

8. }

3.Linux I2C設備驅動的數據傳輸

I2C設備上讀寫數據的時序和數據通常通過i2c_msg數組組織,最後i2c_transfer()函數完成,代碼清單35所示爲一個讀取指定偏移offs寄存器的例子。

代碼清單35 I2C設備驅動數據傳輸範例

1. struct i2c_msg msg[2];

2. /*第一條消息是寫消息*/

3. msg[0].addr = client->addr;

4. msg[0].flags = 0;

5. msg[0].len = 1;

6. msg[0].buf = &offs;

7. /*第二條消息是讀消息*/

8. msg[1].addr = client->addr;

9. msg[1].flags = I2C_M_RD;

10. msg[1].len = sizeof(buf);

11. msg[1].buf = &buf[0];

i2c_transferclient->adapter, msg, 2;

4.Linuxi2c-dev.c文件分析

I2c_dev.c文件完全可以被看作一個I2C設備驅動,不過,它實現的一個i2c_client是虛擬、臨時的、隨着設備文件的打開而產生,並隨着設備文件的關閉而撤銷,並沒有被添加到i2c_adapterclient鏈表中。i2c-dev.c針對每個I2C適配器生成一個主設備號爲89的設備文件,實現了i2c_driver的成員函數以及文件操作接口,所以i2c-dev.c的主體是“i2c_driver成員函數+字符設備驅動”。

i2c-dev.c中提供i2cdev_read()i2cdev_write()函數來對應用戶空間要使用的read()write()文件操作接口,這兩個函數分別調用I2C核心的i2c_master_recv()i2c_master_send()函數來構造一條I2C消息並引發適配器algorithm通信函數的調用,完成消息的傳輸,對應於圖所示的時序。但是很遺憾,大多數稍微複雜一點I2C設備的讀寫流程並不對應於一條消息,往往需要兩條甚至跟多的消息來進行一次讀寫週期(即如圖所示的重複開始位RepStart模式),這種情況下,在應用層仍然調用read()write()文件API來讀寫I2C設備,將不能正確地讀寫。許多工程師碰到過類似的問題,往往經過相當長時間的調試都沒法解決I2C設備的讀寫,連錯誤的原因也無法找到,顯然是對i2cdev_read()i2cdev_write()函數的作用有所誤解。

 

7 i2cdev_read()i2cdev_write()函數對應的時序

 

8 RepStart模式

鑑於上述的原因,i2c-dev.ci2cdev_read()i2cdev_write()函數不具備太強的通用性,沒有太大的實用價值,只能實用於非RepStart模式的情況。對於兩條以上消息組成的讀寫,在用戶空間需要組織i2c_msg消息數組並調用I2C_RDWRIOCTL命令。代碼清單36所示i2cdev_ioctl()函數的框架。

代碼清單36 i2c-dev.c中的i2cdev_ioctl函數

1. static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

2. {

3.     struct i2c_client *client = file->private_data;

4.     unsigned long funcs;

5.     dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",

6.         cmd, arg);

7.     switch (cmd) {

8.     case I2C_SLAVE:

9.     case I2C_SLAVE_FORCE:

10.         /* NOTE:  devices set up to work with "new style" drivers

11.          * can't use I2C_SLAVE, even when the device node is not

12.          * bound to a driver.  Only I2C_SLAVE_FORCE will work.

13.          *

14.          * Setting the PEC flag here won't affect kernel drivers,

15.          * which will be using the i2c_client node registered with

16.          * the driver model core.  Likewise, when that client has

17.          * the PEC flag already set, the i2c-dev driver won't see

18.          * (or use) this setting.

19.          */

20.         if ((arg > 0x3ff) ||

21.             (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))

22.             return -EINVAL;

23.         if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg))

24.             return -EBUSY;

25.         /* REVISIT: address could become busy later */

26.         client->addr = arg;

27.         return 0;

28.     case I2C_TENBIT:

29.         if (arg)

30.             client->flags |= I2C_M_TEN;

31.         else

32.             client->flags &= ~I2C_M_TEN;

33.         return 0;

34.     case I2C_PEC:

35.         if (arg)

36.             client->flags |= I2C_CLIENT_PEC;

37.         else

38.             client->flags &= ~I2C_CLIENT_PEC;

39.         return 0;

40.     case I2C_FUNCS:

41.         funcs = i2c_get_functionality(client->adapter);

42.         return put_user(funcs, (unsigned long __user *)arg);

43.     case I2C_RDWR:

44.         return i2cdev_ioctl_rdrw(client, arg);

45.     case I2C_SMBUS:

46.         return i2cdev_ioctl_smbus(client, arg);

47.     case I2C_RETRIES:

48.         client->adapter->retries = arg;

49.         break;

50. case I2C_TIMEOUT:

51.         /* For historical reasons, user-space sets the timeout

52.          * value in units of 10 ms.

53.          */

54.         client->adapter->timeout = msecs_to_jiffies(arg * 10);

55.         break;

56.     default:

57.         /* NOTE:  returning a fault code here could cause trouble

58.          * in buggy userspace code.  Some old kernel bugs returned

59.          * zero in this case, and userspace code might accidentally

60.          * have depended on that bug.

61.          */

62.         return -ENOTTY;

63.     }

64.     return 0;

65. }

常用的IOCTL包含I2C_SLAVE(設備從設備地址)、I2C_RETRIES(沒有收到設備ACK情況下的重試次數,默認爲1)、I2C_TIMEOUT以及I2C_RDWR

5.AT24C02 EEPROMI2C設備驅動實例

I2c設備驅動(也稱爲客戶驅動)是對I2c硬件體系結構中設備端的實現,我們這裏是AT24C02I2c設備驅動,設備一般掛接在受CPU控制的I2c適配器上,通過I2c適配器與CPU交換數據。

drivers/misc/eeprom/at24.c文件支持大多數I2C接口的EEPROM,正如我們前面所述,一個具體的I2C設備驅動有兩部分組成,一部分是i2c_driver,用於將設備掛接於I2C總線,一部分是設備本身的驅動。對於EEPROM而言,設備本身的驅動以bin_attribute二進制sysfs結點形式呈現。代碼清單37給出了該驅動的框架。

代碼清單37 at24_bin_read()函數

1. static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,

2.         struct bin_attribute *attr,

3.         char *buf, loff_t off, size_t count)

4. {

5.     struct at24_data *at24;

6. 

7.     at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));

8.     return at24_read(at24, buf, off, count);

9. }

代碼清單38 at24_bin_write()函數

1. /*

2.  * Note that if the hardware write-protect pin is pulled high, the whole

3.  * chip is normally write protected. But there are plenty of product

4.  * variants here, including OTP fuses and partial chip protect.

5.  *

6.  * We only use page mode writes; the alternative is sloooow. This routine

7.  * writes at most one page.

8.  */

9. static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,

10.         unsigned offset, size_t count)

11. {

12.     struct i2c_client *client;

13.     struct i2c_msg msg;

14.     ssize_t status;

15.     unsigned long timeout, write_time;

16.     unsigned next_page;

17. 

18.     /* Get corresponding I2C address and adjust offset */

19.     client = at24_translate_offset(at24, &offset);

20. 

21.     /* write_max is at most a page */

22.     if (count > at24->write_max)

23.         count = at24->write_max;

24. 

25.     /* Never roll over backwards, to the start of this page */

26.     next_page = roundup(offset + 1, at24->chip.page_size);

27.     if (offset + count > next_page)

28.         count = next_page - offset;

29. 

30.     /* If we'll use I2C calls for I/O, set up the message */

31.     if (!at24->use_smbus) {

32.         int i = 0;

33. 

34.         msg.addr = client->addr;

35.         msg.flags = 0;

36. 

37.         /* msg.buf is u8 and casts will mask the values */

38.         msg.buf = at24->writebuf;

39.         if (at24->chip.flags & AT24_FLAG_ADDR16)

40.             msg.buf[i++] = offset >> 8;

41. 

42.         msg.buf[i++] = offset;

43.         memcpy(&msg.buf[i], buf, count);

44.         msg.len = i + count;

45.     }

46. 

47.     /*

48.      * Writes fail if the previous one didn't complete yet. We may

49.      * loop a few times until this one succeeds, waiting at least

50.      * long enough for one entire page write to work.

51.      */

52.     timeout = jiffies + msecs_to_jiffies(write_timeout);

53.     do {

54.         write_time = jiffies;

55.         if (at24->use_smbus) {

56.             status = i2c_smbus_write_i2c_block_data(client,

57.                     offset, count, buf);

58.             if (status == 0)

59.                 status = count;

60.         } else {

61.             status = i2c_transfer(client->adapter, &msg, 1);

62.             if (status == 1)

63.                 status = count;

64.         }

65.         dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n",

66.                 count, offset, status, jiffies);

67. 

68.         if (status == count)

69.             return count;

70. 

71.         /* REVISIT: at HZ=100, this is sloooow */

72.         msleep(1);

73.     } while (time_before(write_time, timeout));

74. 

75.     return -ETIMEDOUT;

76. }

代碼清單39 i2c_device_id結構體

1. static const struct i2c_device_id at24_ids[] = {

2.     /* needs 8 addresses as A0-A2 are ignored */

3.     { "24c00", AT24_DEVICE_MAGIC(128 / 8, AT24_FLAG_TAKE8ADDR) },

4.     /* old variants can't be handled with this generic entry! */

5.     { "24c01", AT24_DEVICE_MAGIC(1024 / 8, 0) },

6.     { "24c02", AT24_DEVICE_MAGIC(2048 / 8, 0) },

7.     /* spd is a 24c02 in memory DIMMs */

8.     { "spd", AT24_DEVICE_MAGIC(2048 / 8,

9.         AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },

10.     { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) },

11.     /* 24rf08 quirk is handled at i2c-core */

12.     { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) },

13.     { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) },

14.     { "24c32", AT24_DEVICE_MAGIC(32768 / 8, AT24_FLAG_ADDR16) },

15.     { "24c64", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16) },

16.     { "24c128", AT24_DEVICE_MAGIC(131072 / 8, AT24_FLAG_ADDR16) },

17.     { "24c256", AT24_DEVICE_MAGIC(262144 / 8, AT24_FLAG_ADDR16) },

18.     { "24c512", AT24_DEVICE_MAGIC(524288 / 8, AT24_FLAG_ADDR16) },

19.     { "24c1024", AT24_DEVICE_MAGIC(1048576 / 8, AT24_FLAG_ADDR16) },

20.     { "at24", 0 },

21.     { /* END OF LIST */ }

22. };

23. MODULE_DEVICE_TABLE(i2c, at24_ids);

代碼清單40 初始化at24xx設備的i2c_driver結構體

1. /*-------------------------------------------------------------------------*/

2. 

3. static struct i2c_driver at24_driver = {

4.     .driver = {

5.         .name = "at24",

6.         .owner = THIS_MODULE,

7.     },

8.     .probe = at24_probe,

9.     .remove = __devexit_p(at24_remove),

10.     .id_table = at24_ids,

11. };

代碼清單41 at24_probe函數

1. static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)

2. {

3.     struct at24_platform_data chip;

4.     bool writable;

5.     int use_smbus = 0;

6.     struct at24_data *at24;

7.     int err;

8.     unsigned i, num_addresses;

9.     kernel_ulong_t magic;

10. 

11.     if (client->dev.platform_data) {

12.         chip = *(struct at24_platform_data *)client->dev.platform_data;

13.     } else {

14.         if (!id->driver_data) {

15.             err = -ENODEV;

16.             goto err_out;

17.         }

18.         magic = id->driver_data;

19.         chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));

20.         magic >>= AT24_SIZE_BYTELEN;

21.         chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);

22.         /*

23.          * This is slow, but we can't know all eeproms, so we better

24.          * play safe. Specifying custom eeprom-types via platform_data

25.          * is recommended anyhow.

26.          */

27.         chip.page_size = 1;

28. 

29.         /* update chipdata if OF is present */

30.         at24_get_ofdata(client, &chip);

31. 

32.         chip.setup = NULL;

33.         chip.context = NULL;

34.     }

35. 

36.     if (!is_power_of_2(chip.byte_len))

37.         dev_warn(&client->dev,

38.             "byte_len looks suspicious (no power of 2)!\n");

39.     if (!chip.page_size) {

40.         dev_err(&client->dev, "page_size must not be 0!\n");

41.         err = -EINVAL;

42.         goto err_out;

43.     }

44.     if (!is_power_of_2(chip.page_size))

45.         dev_warn(&client->dev,

46.             "page_size looks suspicious (no power of 2)!\n");

47.         

48.     /* Use I2C operations unless we're stuck with SMBus extensions. */

49.     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {

50.         if (chip.flags & AT24_FLAG_ADDR16) {

51.             err = -EPFNOSUPPORT;

52.             goto err_out;

53.         }   

54.         if (i2c_check_functionality(client->adapter,

55.                 I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {

56.             use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;

57.         } else if (i2c_check_functionality(client->adapter,

58.                 I2C_FUNC_SMBUS_READ_WORD_DATA)) {

59.             use_smbus = I2C_SMBUS_WORD_DATA;

60.         } else if (i2c_check_functionality(client->adapter,

61.                 I2C_FUNC_SMBUS_READ_BYTE_DATA)) {

62.             use_smbus = I2C_SMBUS_BYTE_DATA;

63.         } else {

64.             err = -EPFNOSUPPORT;

65.             goto err_out;

66.         }

67.     }

68. 

69.     if (chip.flags & AT24_FLAG_TAKE8ADDR)

70.         num_addresses = 8;

71.     else

72.         num_addresses = DIV_ROUND_UP(chip.byte_len,

73.             (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);

74. 

75.     at24 = kzalloc(sizeof(struct at24_data) +

76.         num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);

77.     if (!at24) {

78.         err = -ENOMEM;

79.         goto err_out;

80.     }

81. 

82.     mutex_init(&at24->lock);

83.     at24->use_smbus = use_smbus;

84.     at24->chip = chip;

85.     at24->num_addresses = num_addresses;

86. 

87.     /*

88.      * Export the EEPROM bytes through sysfs, since that's convenient.

89.      * By default, only root should see the data (maybe passwords etc)

90.      */

91.     sysfs_bin_attr_init(&at24->bin);

92.     at24->bin.attr.name = "eeprom";

93.     at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;

94.     at24->bin.read = at24_bin_read;

95. at24->bin.size = chip.byte_len;

96. 

97.     at24->macc.read = at24_macc_read;

98. 

99.     writable = !(chip.flags & AT24_FLAG_READONLY);

100.     if (writable) {

101.         if (!use_smbus || i2c_check_functionality(client->adapter,

102.                 I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {

103. 

104.             unsigned write_max = chip.page_size;

105. 

106.             at24->macc.write = at24_macc_write;

107. 

108.             at24->bin.write = at24_bin_write;

109.             at24->bin.attr.mode |= S_IWUSR;

110. 

111.             if (write_max > io_limit)

112.                 write_max = io_limit;

113.             if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)

114.                 write_max = I2C_SMBUS_BLOCK_MAX;

115.             at24->write_max = write_max;

116. 

117.             /* buffer (data + address at the beginning) */

118.             at24->writebuf = kmalloc(write_max + 2, GFP_KERNEL);

119.             if (!at24->writebuf) {

120.                 err = -ENOMEM;

121.                 goto err_struct;

122.             }

123.         } else {

124.             dev_warn(&client->dev,

125.                 "cannot write due to controller restrictions.");

126.         }

127.     }

128. 

129.     at24->client[0] = client;

130. 

131.     /* use dummy devices for multiple-address chips */

132.     for (i = 1; i < num_addresses; i++) {

133.         at24->client[i] = i2c_new_dummy(client->adapter,

134.                     client->addr + i);

135.         if (!at24->client[i]) {

136.             dev_err(&client->dev, "address 0x%02x unavailable\n",

137.                     client->addr + i);

138.             err = -EADDRINUSE;

139.             goto err_clients;

140.         }

141. }

142.     err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);

143.     if (err)

144.         goto err_clients;

145. 

146.     i2c_set_clientdata(client, at24);

147. 

148.     dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n",

149.         at24->bin.size, client->name,

150.         writable ? "writable" : "read-only", at24->write_max);

151.     if (use_smbus == I2C_SMBUS_WORD_DATA ||

152.         use_smbus == I2C_SMBUS_BYTE_DATA) {

153.         dev_notice(&client->dev, "Falling back to %s reads, "

154.                "performance will suffer\n", use_smbus ==

155.                I2C_SMBUS_WORD_DATA ? "word" : "byte");

156.     }

157. 

158.     /* export data to kernel code */

159.     if (chip.setup)

160.         chip.setup(&at24->macc, chip.context);

161. 

162.     return 0;

163. 

164. err_clients:

165.     for (i = 1; i < num_addresses; i++)

166.         if (at24->client[i])

167.             i2c_unregister_device(at24->client[i]);

168. 

169.     kfree(at24->writebuf);

170. err_struct:

171.     kfree(at24);

172. err_out:

173.     dev_dbg(&client->dev, "probe error %d\n", err);

174.     return err;

175. }

176. 

177. 代碼清單42 at24_remove函數

178. static int __devexit at24_remove(struct i2c_client *client)

179. {

180.     struct at24_data *at24;

181.     int i;

182. 

183.     at24 = i2c_get_clientdata(client);

184.     sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);

185. 

186.     for (i = 1; i < at24->num_addresses; i++)

187.         i2c_unregister_device(at24->client[i]);

188. 

189.     kfree(at24->writebuf);

190.     kfree(at24);

191.     return 0;

192. }

代碼清單43 at24xx設備驅動模塊的加載和卸載函數

1. static int __init at24_init(void)

2. {

3.     if (!io_limit) {

4.         pr_err("at24: io_limit must not be 0!\n");

5.         return -EINVAL;

6.     }   

7.         

8.     io_limit = rounddown_pow_of_two(io_limit);

9.     return i2c_add_driver(&at24_driver);

10. }   

11. module_init(at24_init);

12. 

13. static void __exit at24_exit(void)

14. {

15.     i2c_del_driver(&at24_driver);

16. }

17. module_exit(at24_exit);

18. 

19. MODULE_DESCRIPTION("Driver for most I2C EEPROMs");

20. MODULE_AUTHOR("David Brownell and Wolfram Sang");

21. MODULE_LICENSE("GPL");

At24_bin_read()at24_bin_write()倆個函數是EEPROM驅動本身的讀寫實現即bin_attribute驅動,之後一部分是i2c_driver,兩者在i2c_driverprobe()、remove函數中建立關聯。I2c_driverprobe()函數中的初始化並通過sysfs_create_bin_file()註冊了二進制sysfs結點,而remove()函數則通過sysfs_remove_bin_file()註銷了sysfs結點。

6.添加板級信息

drivers/misc/eeprom/at24.c不依賴於具體的CPUI2C控制寄存器硬件特性,因此,如果某一電路板包含該外設,只需要在板文件中添加對應的i2c_board_info,如對於s3c2440要使其支持at24c02 eeprom只需要作如下工作:

首先是要在內核中註冊板級信息,因爲設備和驅動需要匹配,它們是通過設備名和驅動名進行匹配的。因爲AT24C02芯片是由2048bits構成,所以有2048 / 8 = 256byte,並將其分成32頁每頁有8byte大小,是8bits尋址,如果AT24C02芯片的A0A1,A2,這三個引腳接地,着AT24C02芯片從地址是01010000b(0x50),如果AT24C02芯片的A0結高電平,A1A2兩個引腳接地,着AT24C02芯片從地址是01010001b(0x51),這些都是AT24C02datasheet上有的,不同芯片不同情況。下面在linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c添加AT24C02設備的板級信息如下:

1. [fulinux@ubuntu linux-3.0]$ vim arch/arm/mach-s3c2440/mach-smdk2440.c 

2.  #include <linux/i2c.h>     

3. #include <linux/i2c/at24.h> 

4. 

5. static struct at24_platform_data at24c02= {

6.      .byte_len   = SZ_2K / 8,

7.      .page_size  = 8,

8.      .flags      = AT24_FLAG_ADDR8,

9. };

10.  

11.  static struct i2c_board_info __initdata smdk2440_i2c_devs[] = {

12.      {

13.          I2C_BOARD_INFO("24c02", 0x50),

14.          .platform_data = &at24c02,

15.      },

16.      /*  more devices can be added using expansion connectors */

17. };

********************************************************************************************

裝載聲明:希望大家能轉載此文謝謝:原文鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章