轉至: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個不同的驅動函數:
- 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()
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
- 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;
- };
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
- 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;
- };
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
- 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;
- };
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
- 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 *);
- };
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也非常關鍵,調用驅動中的發送接收函數需要填充該結構體
- /*
- * 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 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
- 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);
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()函數真正的驅動硬件流程,代碼清單如下,不重要的已刪除。
- 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;
- }
- }
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設備驅動時,需要調用下列函數。程序清單如下- int i2c_attach_client(struct i2c_client *client)
- {
- ...
- device_register(&client->dev);
- device_create_file(&client->dev, &dev_attr_client_name);
- ...
- return 0;
- }
int i2c_attach_client(struct i2c_client *client)
{
...
device_register(&client->dev);
device_create_file(&client->dev, &dev_attr_client_name);
...
return 0;
}
- int i2c_detach_client(struct i2c_client *client)
- {
- ...
- device_remove_file(&client->dev, &dev_attr_client_name);
- device_unregister(&client->dev);
- ...
- return res;
- }
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中有調用,稍後分析- /* -----
- * 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);
- }
- ...
- }
/* -----
* 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);
}
...
}
- 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);
- }
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總線驅動,這部分代碼是這樣添加到系統中的- 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);
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適配器- static struct i2c_algorithm i2c_davinci_algo = {
- .master_xfer = i2c_davinci_xfer,
- .functionality = i2c_davinci_func,
- };
static struct i2c_algorithm i2c_davinci_algo = {
.master_xfer = i2c_davinci_xfer,
.functionality = i2c_davinci_func,
};
然後在davinci_i2c_probe函數中,將i2c_davinci_algo添加到添加到algorithm系統中
- 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,因此源碼中存在支持多個設備地址的機制。
該字符設備的用到的結構體有兩個,如下
- 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;
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;
- #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;
#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,在驅動的多個地方均需要它。
下面先從字符設備的基本框架入手,然後深入該驅動的細節部分。
首先是該字符設備的初始化和退出函數
- 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,
- };
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代碼展示(將影響結構條理的代碼去掉,稍後在做詳細分析)
- 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;
- }
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()函數源碼
- 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;
- }
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()
- 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;
- }
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抽取出來的
- driver->driver.name = pObj->name;
- driver->id = I2C_DRIVERID_MISC;
- driver->attach_adapter = I2C_attachAdapter;
- 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有這樣的說明:
- /* 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.
- */
/* 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由內核驅動自動調用,我們只需在調用的時候實現必要的功能即可,如下代碼展示- 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;
- }
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的說明如下:
- /* 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.
- */
/* 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設備的連接
- 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;
- }
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_adapter和I2c_algorithm結構體,I2c設備驅動填充I2c_driver和i2c_client結構體並實現其本身所對應設備類型的驅動。
2.I2C總線驅動
I2C總線驅動是對I2C硬件體系結構中適配器的實現,適配器可由CPU控制,甚至可以直接集成在CPU內部。
I2C總線驅動主要包含了I2C適配器數據結構i2c_adapter、I2C適配器的algorithm數據結構i2c_algorithm和控制I2C適配器產生通信信號的函數。
經由I2C總線驅動的代碼,我們可以控制I2C適配器以主控制方式產生開始、停止位、讀寫週期,以及以從設備方式讀寫、產生ACK等。
3.I2C設備驅動
I2C設備驅動(也稱爲客戶端驅動)是對I2C硬件體系結構中設備端的實現,設備一般掛接在受CPU控制的I2C適配器上,通過I2C適配器與CPU交換數據。
I2C設備驅動主要包含了數據結構體i2c_driver和i2c_client,我們需要具體設備實現其中的成員函數。
圖1 I2C驅動體系結構圖1
圖2 I2C驅動體系結構圖2
另外,系統中i2c-dev.c文件定義的主設備號爲89的設備可以方便地給應用程序提供讀寫I2c設備寄存器的能力,使得工程師大多數時候並不需要爲具體的I2c設備驅動定義文件操作接口。
如何理解adapter和client呢?它在s3c2440中對應的是什麼?Adapter和client都是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芯片AT24C02和linux-3.0內核平臺講解I2c的三個部分。
********************************************************************************************
轉載聲明:希望大家能轉載此文謝謝 原文鏈接
********************************************************************************************
4.s3c2440和at24c02硬件特性
請看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_driver、i2c_client、i2c_adapter和i2c_algorithm着4個數據結構進行了定義。理解這4個結構的作用十分關鍵,代碼清單1、2、3、4分別給出了它們的定義。
代碼清單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_driver、i2c_client、i2c_adapter和i2c_algorithm這4個數據結構的作用及盤根錯節的關係。
(1)2c_adapter與i2c_algorithm
i2c_adapter對應於物理上的一個適配器,而i2c_algorithm對應一套通信方法。一個I2C適配器需要i2c_algorithm中提供的通信函數來控制適配器上產生特定的訪問週期。缺少i2c_algorithm的i2c_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_driver與i2c_client
i2c_driver對應一套驅動方法,其主要成員函數是probe()、remove()、suspend()、resume()等,另外id_table是該驅動所支持的I2C設備的ID表。i2c_client對應於真實的物理設備,每個I2C設備都需要一個i2c_client來描述。I2c_driver和i2c_client的關係是一對多,一個i2c_driver上可以支持多個同類型的i2c_client。
I2c_client信息通常在BSP的板文件中通過i2c_board_info填充,如下面代碼就定義了一個I2C設備ID爲“24c02”、地址爲0x50的i2c_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_type的match()函數i2c_device_match()中,會調用i2c_match_id()函數匹配板文件中定義的ID和i2c_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_adpater與i2c_client
i2c_adapter與i2c_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適配器(如申請I2C的I/O地址和中斷號)、驅動CPU控制的I2C適配器從硬件上產生各種信號以及處理I2C中斷等。
提供I2C適配器的algorithm,具體適配器的xxx_xfer()函數填充i2c_algorithm的master_xfer指針,並把i2c_algorithm指針賦值給i2c_adapter的algo指針。
實現I2C設備驅動中的i2c_driver接口,具體設備yyy_probe()、yyy_remove()、yyy_suspend()、yyy_resume()函數指針和i2c_device_id設備ID表賦值給i2c_driver的probe、remove、suspend、resume和id_table指針。
實現I2C設備所對應類型的具體驅動,i2c_driver只是實現設備與總線的掛接,而掛接在總線上的設備則是千差萬別的。例如,如果字符設備,就實現文件操作接口,即實現具體yyy的yyy_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_algorithm的master_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()函數的實現都與具體的CPU和I2C適配器硬件直接相關。
2.I2C總線通信方法
我們需要爲特定的I2C適配器實現其通信方法,主要實現i2c_algorithm的master_xfer()函數和functionality()函數。
Functionality()函數非常簡單,用於返回algorithm所支持的通信協議,如I2C_FUNC_I2C、I2C_FUNC_10BIT_ADDR、I2C_FUNC_SMBUS_READ_BYTE、I2C_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_adapter的algo_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. };
對於s3c2440的i2c模塊而言內核中做了如下的工作:
S3c2440處理器內部集成了一個I2C控制器,通過4個寄存器就可以方便地對其進行控制,這4個寄存器如下:
l IICCON:I2C控制寄存器。
l IICSTAT:I2C狀態寄存器。
l IICDS:I2C收發數據移位寄存器。
l IICADD:I2C地址寄存器。
S3c2440處理器內部集成的I2C控制器可支持主、從兩種模式,我們主要使用其主模式。通過對IICCON、IICDS和IICADD寄存器的操作,可
在I2C總線上產生開始位、停止位、數據和地址,而傳輸的狀態則通過IICSTAT寄存器獲取。
3.s3c2440 I2C 總線驅動總體分析
s3c_2440的I2C總線驅動driver/i2c/busses/i2c-s3c2410.c支持s3c24xx、s3c64xx、s5pc1xx和s5p64xx處理器,在我們使用的3.0內核版本中,其名稱任然叫2410,顯然是歷史原因引起的。它主要完成以下工作。
設計對應於i2c_adapter_xxx_init()模板的s3c_2440的模塊加載函數和對應於i2c_adapter_xxx_exit()函數模板的模塊卸載函數。
設計對應於i2c_adapter_xxx_xfer()模板的s3c_2440適配器的通信方法函數。
針對s3c24xx、s3c64xx、s5pc1xx和s5p64xx處理器,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_driver的remove指針方式被調用。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 總線通信方法
由代碼清單25的23行可以看出,I2C適配器對應的i2c_algorithm結構體實例爲s3c24xx_i2c_algorithm,代碼清單28所示爲s3c24xx_i2c_algorithm的定義。
代碼清單28 s3c2440的i2c_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()首先將s3c2440的I2C適配器設置爲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()函數通過switch(i2c->state)的不同狀態進行處理,在每種狀態下,先檢查i2c->state的狀態與硬件寄存器應該處於的狀態是否一致,如果不一致,則證明有誤,直接返回。當I2C處於讀狀態STATE_READ或是寫狀態STATE_WRITE時,通過is_lastmsg()函數判斷是否傳輸的最後一條I2C消息,如果是,則產生停止位,否則通過i2c->msg_idx++、i2c->msg++推進到下一條消息。
四、I2C的第三部分
1.Linux I2C 設備驅動
I2C設備驅動要使用i2c_driver和i2c_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_transfer(client->adapter, msg, 2);
4.Linux的i2c-dev.c文件分析
I2c_dev.c文件完全可以被看作一個I2C設備驅動,不過,它實現的一個i2c_client是虛擬、臨時的、隨着設備文件的打開而產生,並隨着設備文件的關閉而撤銷,並沒有被添加到i2c_adapter的client鏈表中。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.c中i2cdev_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 EEPROM的I2C設備驅動實例
I2c設備驅動(也稱爲客戶驅動)是對I2c硬件體系結構中設備端的實現,我們這裏是AT24C02的I2c設備驅動,設備一般掛接在受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_driver的probe()、remove函數中建立關聯。I2c_driver的probe()函數中的初始化並通過sysfs_create_bin_file()註冊了二進制sysfs結點,而remove()函數則通過sysfs_remove_bin_file()註銷了sysfs結點。
6.添加板級信息
drivers/misc/eeprom/at24.c不依賴於具體的CPU和I2C控制寄存器硬件特性,因此,如果某一電路板包含該外設,只需要在板文件中添加對應的i2c_board_info,如對於s3c2440要使其支持at24c02 eeprom只需要作如下工作:
首先是要在內核中註冊板級信息,因爲設備和驅動需要匹配,它們是通過設備名和驅動名進行匹配的。因爲AT24C02芯片是由2048bits構成,所以有2048 / 8 = 256byte,並將其分成32頁每頁有8byte大小,是8bits尋址,如果AT24C02芯片的A0,A1,A2,這三個引腳接地,着AT24C02芯片從地址是01010000b(即0x50),如果AT24C02芯片的A0結高電平,A1,A2兩個引腳接地,着AT24C02芯片從地址是01010001b(即0x51),這些都是AT24C02的datasheet上有的,不同芯片不同情況。下面在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. };
********************************************************************************************
裝載聲明:希望大家能轉載此文謝謝:原文鏈接