linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)
最近工作中又使用到了I2C,所以借S3C2440開發板GT2440為硬件平臺溫習一遍I2C驅動體系。
linux內核中IIC驅動的體系框架
linux內核中IIC部分驅動代碼位于:/drivers/i2c下,代碼大致分為幾個小目錄及i2c目錄下的的i2c核心代碼:
核心代碼:/drivers/i2c/i2c-core.c?/drivers/i2c/i2c-core.h
busses目錄:各種IIC控制器相關的驅動代碼(也稱為IIC總線驅動代碼),如果S3C2440A內部集成了IIC控制器,它在busses目錄下對應的控制器驅動代碼為i2c-s3c2410.c
algos目錄:定義的是一些通信方法,對于S3C2440A的IIC控制器的通信方法沒在里面
muxes目錄:各種外接在IIC控制器上的IIC從設備相關的驅動代碼
從以上的目錄我們可以看出,linux內IIC驅動體系分為3部分:IIC核心、IIC總線驅動、IIC設備驅動。
IIC核心:
IIC核心定義了各種數據結構及抽象出通用接口函數:
如注冊(銷)IIC適配器:
i2c_add_adapter(struct?i2c_adapter?*adapter);
i2c_del_adapter(struct?i2c_adapter?*adapter);
注冊(銷)IIC設備驅動:
i2c_register_drive(struct?module?*owner?,struct?i2c_driver?*driver);
i2c_del_driver(struct?i2c_driver?*driver);
IIC抽象的傳輸、發送和接收函數:
i2c_transfe(struct?i2c_adapter?*adapter,struct?i2c_msg?*msg,int?num);
i2c_master_send(struct?i2c_client?*client,const?char?*buf,int?count);
i2c_master_recv(struct?i2c_client?*client?,?char?*?buf?,?int?count);
IIC總線驅動:
IIC總線驅動及IIC控制器驅動,為此linux內核中定義一個i2c_adapter數據結構來描述一個IIC適配器,而在不同架構上有不同實現方法:如S3C2440A上就使用i2c-s3c2410.c來實現了S3C2440A上的IIC控制器驅動
IIC設備驅動:
IIC設備在linux內核中用struct?i2c_client結構來描述,而使用i2c_driver結構來描述掛載在IIC控制器上的IIC從設備如何與主機進行通信。
問:像IIC裸機驅動那樣一個文件就能搞定的IIC驅動在linux中的結構卻相當的復雜?
原因在于linux內核,IIC驅動是一類驅動,如果像裸機驅動那樣,那么這個驅動只能用于特定的IIC控制器及IIC設備,這樣一來如果有很多不同類型的IIC控制器或IIC設備,那么所有的代碼都必須重寫。這顯然是不明智的,一個簡單的方法是將不同類型的IIC控制器及IIC設備之間進行通信的共同點給抽象出來,而這部分的代碼不管是任何IIC控制器或IIC設備都是一樣的,這樣移植不同的IIC總線驅動和IIC設備驅動時就能大大的減小代碼量。就像內核中將IIC驅動分成了IIC總線驅動和IIC設備驅動一樣,在裸機驅動中我們根本看不出那部分是總線驅動,哪部分是設備驅動?二者已經融為了一體。這樣的缺陷也很明顯,當我們的IIC總線上掛載了不同的IIC設備時,那么我們不得不重新寫IIC控制器相關的驅動代碼,而如果把它抽象出來,IIC總線驅動主要負責IIC總線的數據傳輸,如時鐘控制、發出S/P信號、中斷處理等等,而IIC設備驅動從負責解析出傳輸的這些數據的含義,因為對于不同的IIC設備,其總線上傳輸的這些數據的含義不同。個人認為linux的驅動的體系也是基于這種思想產生的。當我們明白了IIC驅動框架中如此負責的構造的良苦用心自然會更加深刻將整個驅動框架銘記于心。
Linux內核為IIC構造的幾個重要的數據結構:
struct i2c_adapter {
struct module *owner;
unsigned int id __deprecated;
unsigned int
class;?適配器所屬的類?const struct i2c_algorithm *algo;
該總線上的通信方法?void
*algo_data;?通信方法的附加數據
struct rt_mutex
bus_lock;?對所有設備的鎖結構
int
timeout;?超時時間,在搞總線上發送信號多久沒回的超時時間?int
retries;?重復的次數?struct device
dev;?適配器設備
int
nr;?總線的編號?char
name[48];?名字?struct completion dev_released;
struct mutex
userspace_clients_lock;
struct list_head userspace_clients;
};
其中重要的成員有algo?:該成員所指向的i2c_algorithm實際上就是具體的IIC控制器的通信方法,如發出S/P信號、傳輸數據等最底層的控制器操作。
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int num);?消息發送函數指針?int (*smbus_xfer) (struct i2c_adapter *adap, u16
addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);
u32 (*functionality) (struct i2c_adapter
*);?適配器所支持的功能
};
由于每種適配器所支持的功能不同、傳輸數據的方法也不同,所以講這個抽象出來,在不同的適配器中再去具體的實現它。
struct i2c_driver {
unsigned int class;
int (*attach_adapter)(struct i2c_adapter
*);
int (*detach_adapter)(struct i2c_adapter
*);
標準的驅動模型?int (*probe)(struct i2c_client *, const struct
i2c_device_id *);
int (*remove)(struct i2c_client *);
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t
mesg);
int (*resume)(struct i2c_client
*);
void (*alert)(struct i2c_client *, unsigned int
data);
類似ioctl?int (*command)(struct i2c_client *client,
unsigned int cmd, void *arg);
用于設備驅動模型?struct device_driver driver;
列出該設備驅動所支持的設備?const struct i2c_device_id
*id_table;
設備探測的回調函數?int (*detect)(struct i2c_client *, struct
i2c_board_info *);
用于探測的i2c設備地址?const unsigned short *address_list;
鏈接所有探測出的i2c設備?struct list_head clients;
};
struct i2c_client
{?i2c_client 代表i2c從設備
unsigned short flags;?I2C_CLIENT_TEN表示設備使用的是10位的地址,I2C_CLIENT_PEC表示使用SMBus包用在錯誤檢查
unsigned short
addr;?I2C設備在總線上的的地址?char name[I2C_NAME_SIZE]; 設備名
struct i2c_adapter
*adapter;?指向該I2C設備掛載的I2C適配器
struct i2c_driver
*driver;?指向支持該I2C設備的驅?
struct device
dev;?用于總線設備驅動模型
int
irq;?該設備能產生的中斷號
struct list_head detected;
};
struct i2c_msg
{?I2C總線上傳輸信息的最小單位
__u16 addr;?i2c設備地址,可以是10位的地址,如果是10位的地址flags標志中需設置I2C_M_TEN
__u16 flags; I2C_M_RD
讀標志,所有的適配器都必須支持,其他的標志見I2C_FUNC_*
#define
I2C_M_TEN?0x0010?10位的從設備的地址
#define
I2C_M_RD?0x0001?從I2C設備中讀數據
#define
I2C_M_NOSTART?0x4000?#define
I2C_M_REV_DIR_ADDR?0x2000?#define
I2C_M_IGNORE_NAK?0x1000?#define
I2C_M_NO_RD_ACK?0x0800?#define
I2C_M_RECV_LEN?0x0400?__u16
len;?消息的長度(字節數)
__u8
*buf;?指向消息數據的緩沖區
};
struct
i2c_board_info
{?創建I2C設備的模版
char?type[I2C_NAME_SIZE];?設備類型,用于填充i2c_client.name
unsigned
short?flags;?用于填充i2c_client.flags
unsigned
short?addr;?用于填充i2c_client.addr
void?*platform_data;?存儲i2c_client.dev.platform_data
struct dev_archdata?*archdata;
拷貝到i2c_client.dev.archdata
#ifdef
CONFIG_OF?指向打開固件的設備節點
struct device_node *of_node;
#endif
int?irq;?存儲到i2c_client.irq
};
i2c_board_info
被用來創建當前系統中I2C設備的列表,這些信息用來驅動模型樹,對于主板會使用i2c_register_board_info來注冊這些設備
接下來我們就著手分析linux提供的這些重要數據結構及IIC核心提供的這些核心函數是如何構造出整個IIC驅動框架的,耐心看下去你將對IIC體系驅動框架了如指掌!!!
總結
以上是生活随笔為你收集整理的linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux cat 查看文件内容 不带#
- 下一篇: linux apache配置多线程,li