天天看點

Linux i2c驅動架構分析 (一)Linux的i2c體系結構主要的資料結構

Linux i2c驅動架構分析 (一)

Linux i2c驅動架構分析 (二)

Linux i2c驅動架構分析 (三)

通用i2c裝置驅動分析

Linux的i2c體系結構

Linux的i2c體系結構分為3個組成部分。

(1) i2c核心

i2c核心提供了i2c總線驅動和裝置驅動的注冊、登出方法,i2c通信方法上層的、與具體擴充卡無關的代碼以及探測裝置、檢測裝置位址的上層代碼等。

(2) i2c總線驅動

i2c總線驅動是對i2c硬體體系結構中擴充卡端的實作。

i2c總線驅動主要包含了i2c擴充卡資料結構i2c_adapter、i2c擴充卡的i2c_algorithm資料結構和控制i2c擴充卡産生通信信号的函數。

經由i2c總線驅動的代碼,我們可以控制i2c擴充卡以主要方式産生開始位、停止位、讀寫周期,以及以從裝置方式被讀寫、産生ack等。

(3) i2c裝置驅動

i2c裝置驅動是對i2c硬體體系結構中裝置端的實作,裝置挂接在i2c擴充卡上,通過i2c擴充卡與cpu交換資料。i2c裝置驅動主要包含了資料結構i2c_driver和i2c_client,我們需要根據具體裝置實作其中的成員函數。

i2c驅動架構如下圖所示。

Linux i2c驅動架構分析 (一)Linux的i2c體系結構主要的資料結構

在Linux核心源代碼中的drivers目錄下包含一個i2c目錄,而在i2c目錄下又包含如下檔案和檔案夾:

Linux i2c驅動架構分析 (一)Linux的i2c體系結構主要的資料結構

i2c-core.c,這個檔案實作了i2c核心的功能。

i2c-dev.c,實作了i2c擴充卡裝置檔案的功能,每一個i2c擴充卡都被配置設定一個裝置。

busses檔案夾包含了一些I2C總線的驅動,如針對S3C2410、S3C2440和S3C6410等處理器的i2c控制器驅動為i2c-s3c2410.c。

algos檔案夾,實作了一些i2c總線擴充卡的algorithm。

主要的資料結構

i2c_adapter結構體,描述一個i2c擴充卡(控制器),定義如下:

struct i2c_adapter {
	struct module *owner;
	unsigned int class;		  /* classes to allow probing for */

	//總線通信方法
	const struct i2c_algorithm *algo; /* the algorithm to access the bus */
	void *algo_data;

	/* data fields that are valid for all devices	*/
	const struct i2c_lock_operations *lock_ops;
	struct rt_mutex bus_lock;
	struct rt_mutex mux_lock;

	int timeout;			/* in jiffies */
	int retries;
	struct device dev;		/* the adapter device */

	//總線号
	int nr;

	char name[48];
	struct completion dev_released;

	struct mutex userspace_clients_lock;
	struct list_head userspace_clients;

	struct i2c_bus_recovery_info *bus_recovery_info;
	const struct i2c_adapter_quirks *quirks;
};
           

i2c_algorithm結構體,描述一個擴充卡的總線通信方法:

struct i2c_algorithm {

	//傳輸資料函數
	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
			   int num);

	//SMBus傳輸函數
	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 *);

#if IS_ENABLED(CONFIG_I2C_SLAVE)
	int (*reg_slave)(struct i2c_client *client);
	int (*unreg_slave)(struct i2c_client *client);
#endif
};

           

SMBus大部分基于i2c總線規範,SMBus不需增加額外引腳。與i2c總線相比,SMBus增加了一些新的功能特性,在通路時序也有一定的差異。

i2c_driver結構體,描述一個i2c裝置驅動,定義如下:

struct i2c_driver {
	unsigned int class;

	//老式的探測函數,已不推薦使用
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;

	/* 驅動與适配時,會調用probe函數 */
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	
	......
	
	struct device_driver driver;

	//該驅動所支援的裝置ID
	const struct i2c_device_id *id_table;

	/* 探測函數 */
	int (*detect)(struct i2c_client *, struct i2c_board_info *);

	//探測裝置位址清單
	const unsigned short *address_list;

	//該驅動支援的裝置會通過這個連結清單頭鍊在一起
	struct list_head clients;
}
           

i2c_client結構體,描述一個i2c裝置,定義如下:

struct i2c_client {
	unsigned short flags;		/* div., see below		*/

	//裝置位址
	unsigned short addr;		

	char name[I2C_NAME_SIZE];

	//裝置所挂在的控制器
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/

	struct device dev;		/* the device structure		*/

	int irq;			/* irq issued by device		*/

	//通過這個連結清單節點,挂接在驅動的clients連結清單
	struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};
           

下面梳理一下i2c_driver、i2c_client、i2c_adapter和i2c_algorithm這4個資料結構的作用及其盤根錯節的關系。

  1. i2c_adapter與i2c_algorithm

    i2c_adapter對應于實體上的一個i2c擴充卡,而i2c_algorithm對應一套通信方法。一個i2c擴充卡需要i2c_algorithm中提供的通信函數來控制擴充卡上産生特定的通路周期。缺少 i2c_algorithm的i2c_adapter什麼也做不了,是以i2c_adapter中包含其使用的 i2c_algorithm 的指針。i2c_algorithm中的關鍵函數master_xfer()用于産生i2c通路周期需要的信号,以 i2c_msg為機關。i2c_msg結構體也非常關鍵,代碼清單如下給出了它的定義:

struct i2c_msg {
	__u16 addr;	/* 裝置位址	*/
	__u16 flags;
#define I2C_M_RD		0x0001	/* read data, from slave to master */
														/* I2C_M_RD is guaranteed to be 0x0001! */
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
	__u16 len;		/* 資訊長度				*/
	__u8 *buf;		/* 資訊資料			*/
};
           
  1. 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。

  2. i2c_adpater與i2c_client

    i2c_adpater與i2c_client的關系與i2c硬體體系中擴充卡和裝置的關系一緻,即i2c_client依附于i2c_adpater。由于一個擴充卡上可以連接配接多個I2C裝置,是以一個i2c_adpater也可以被多個i2c_client 依附,i2c_adpater中包括依附于它的i2c_client的連結清單。

繼續閱讀