這部分準備分幾個部分進行分析總結
因為i2c的通訊肯定至少要有2個晶元完成,所以它的驅動是由2大部分組成:
主晶元的i2c的驅動
從晶元的i2c的驅動
注:萬一選的都不支援咋辦???(慘了,只能2個晶元的驅動都得實現了,不過過程差不多)
(一).主晶元的i2c的驅動:(具體如何實現在後面在具體講解)
首先要檢視linux核心是否支援主晶元中i2c驅動器,如果支援就配置一下就ok了,否則要編寫主控晶元的i2c驅動器
編寫方法:
第一.要有i2c匯流排驅動(首先要查查核心i2c檔案是否支援這種匯流排驅動,一般都有支援,如果沒有只好自己倒霉自己寫了)
第二.i2c裝置驅動(主控晶元的位址等等資訊)
這個過程都是差不多的,以後在分析。
一般的主控晶元的i2c控制器linux核心基本上支援的很好,如:2410的i2c驅動器的支援
(二).從晶元的i2c的驅動:
下面主要分析從晶元的i2c驅動(也有2種方式,第乙個是利用核心提供的i2c-dev.c來構建,另乙個是自己寫)
主要分析第一種方式:
利用系統給我們提供的i2c-dev.c來實現乙個i2c介面卡的裝置檔案。然後通過在應用層操作i2c介面卡來控制i2c裝置。
i2c-dev.c並沒有針對特定的裝置而設計,只是提供了通用的read()、write()和ioctl()等介面,應用層可以借用這些介面訪問掛接在介面卡上的i2c裝置的儲存空間或暫存器,並控制i2c裝置的工作方式。但是read和write方法適用性有限。
所以用ioctl方法來操作:
一般都不會使用i2c-dev.c的read()、write()方法。最常用的是ioctl()方法。ioctl()方法可以實現上面所有的情況(兩種資料格式、以及i2c演算法和smbus演算法)。
針對i2c的演算法,需要熟悉
struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是i2c_rdwr。
struct i2c_rdwr_ioctl_data
;struct i2c_msg ;
針對smbus演算法,需要熟悉struct i2c_smbus_ioctl_data。使用的命令是i2c_smbus。對於smbus演算法,不需要考慮「多開始訊號時序」問題。
struct i2c_smbus_ioctl_data ;
首先在核心中已經包含了對s3c2410 中的i2c控制器(匯流排驅動)驅動的支援。提供了i2c演算法(非smbus型別的,所以後面的ioctl的命令是i2c_rdwr)
static const struct i2c_algorithm s3c24xx_i2c_algorithm = ;
另外一方面需要確定為了實現對at24c02 e2prom的操作,需要確定從機晶元的位址及讀寫訪問時序。
在網上找了個例子:
具體分析如下:
#include #include #include #include #include #include #include #include #define i2c_retries 0x0701
#define i2c_timeout 0x0702
#define i2c_rdwr 0x0707
/*********定義struct i2c_rdwr_ioctl_data和struct i2c_msg,要和核心一致。兩個重要的結構體*******/
struct i2c_msg
;struct i2c_rdwr_ioctl_data
;int main()
e2prom_data.nmsgs=2;
/**因為操作時序中,最多是用到2個開始訊號(位元組讀操作中),所以此將
*e2prom_data.nmsgs配置為2
*/e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));
if(!e2prom_data.msgs)
ioctl(fd,i2c_timeout,1);/*超時時間*/
ioctl(fd,i2c_retries,2);/*重複次數*/
/***write data to e2prom**/
/**/
e2prom_data.nmsgs=1;
(e2prom_data.msgs[0]).len=2; //1個 e2prom 寫入目標的位址和1個資料
(e2prom_data.msgs[0]).addr=0x50;//e2prom 裝置位址
(e2prom_data.msgs[0]).flags=0; //write
(e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
(e2prom_data.msgs[0]).buf[0]=0x10;// e2prom 寫入目標的位址
(e2prom_data.msgs[0]).buf[1]=0x58;//the data to write
ret=ioctl(fd,i2c_rdwr,(unsigned long)&e2prom_data);
if(ret<0)
sleep(1);
/******read data from e2prom*******/
e2prom_data.nmsgs=2;
(e2prom_data.msgs[0]).len=1; //e2prom 目標資料的位址
(e2prom_data.msgs[0]).addr=0x50; // e2prom 裝置位址
(e2prom_data.msgs[0]).flags=0;//write
(e2prom_data.msgs[0]).buf[0]=0x10;//e2prom資料位址
(e2prom_data.msgs[1]).len=1;//讀出的資料
(e2prom_data.msgs[1]).addr=0x50;// e2prom 裝置位址
(e2prom_data.msgs[1]).flags=i2c_m_rd;//read
(e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的位址。
(e2prom_data.msgs[1]).buf[0]=0;//初始化讀緩衝
ret=ioctl(fd,i2c_rdwr,(unsigned long)&e2prom_data);
if(ret<0)
printf("buff[0]=%x/n",(e2prom_data.msgs[1]).buf[0]);
close(fd);
i2c_put_adapter(client->adapter);釋放i2c匯流排
return 0;
}
以上講述了一種比較常用的利用i2c-dev.c操作i2c裝置的方法,這種方法可以說是在應用層完成了對具體i2c裝置的驅動工作。
接下來準備具體分析如何寫第一部分!
linux驅動開發擴充套件 i2c子系統核心部分分析
drivers i2c i2c core.c postcore initcall i2c init module exit i2c exit static int init i2c init void endif retval i2c add driver dummy driver 為i2c匯流排新...
對i2c子系統的理解
驅動i2c控制器歸根到底是對iic控制器的暫存器進行讀寫,因此,理解了linux中是怎樣通過層層呼叫來操作iic的暫存器,便理解了整個iic子系統的輪廓。下面以公司使用的重力感測器 bma250 驅動為例來描述這個輪廓。首先介紹三個比較重要的驅動檔案 bma250.c drivers gsensor...
Linux驅動程式設計 基於I2C子系統的I2C驅動
中,我新增了很多注釋,應該不難理解,有錯誤大家可以指出來,我再改正 include include include include include include include define i2c major 365 主裝置號 define i2c minor 0 從裝置號 define i2c...