Linux I2C 子系統

I2C 子系統概述

I2C相關的目錄:linux-3.16.82\drivers\i2c
I2C的頭文件:linux-3.16.82\linux-3.16.82\include\linux\i2c.h \linux-3.16.82\include\trace\events\i2c.h

通俗講解:
I2C driver 代表一類設備的驅動, I2C client 代表一個I2C的設備,實際的設備,I2C adapter 表示一個I2C 的bus
I2C 的bus上可以掛很多的I2C的設備,一個設備對應一個設備驅動,而一個設備驅動可以驅動多個設備
I2C 的dirver 通過註冊將設備驅動添加到i2C bus上,
I2C adapter 可以通過add addapter 將i2C總線控制器的驅動掛載到I2c的bus上, I2c 的驅動和I2C adapter 通過 I2c client進行中間數據傳遞

I2C client 與 I2C driver 通過 id_table進行match。
I2C client 實際上是由I2C adapter創建的。
I2C client 描述設備的從地址,name等。

相關的結構體:
struct i2c_driver {
	unsigned int class;

	/* Notifies the driver that a new bus has appeared. You should avoid
	 * using this, it will be removed in a near future.
	 */
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;

	/* Standard driver model interfaces */
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);   //註冊I2C driver時,設備與driver匹配時的回掉,probe函數完成driver·的初始化
	int (*remove)(struct i2c_client *);

	/* driver model interfaces that don't relate to enumeration  */
	void (*shutdown)(struct i2c_client *);
	int (*suspend)(struct i2c_client *, pm_message_t mesg);
	int (*resume)(struct i2c_client *);

	/* Alert callback, for example for the SMBus alert protocol.
	 * The format and meaning of the data value depends on the protocol.
	 * For the SMBus alert protocol, there is a single bit of data passed
	 * as the alert response's low bit ("event flag").
	 */
	void (*alert)(struct i2c_client *, unsigned int data);

	/* a ioctl like command that can be used to perform specific functions
	 * with the device.
	 */
	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

	struct device_driver driver;                                             設備驅動模型,會在bus/drivers/下的顯示
	const struct i2c_device_id *id_table;                              目前無用,使用devietree時,match主要是匹配driver中的of_device_id

	/* Device detection callback for automatic device creation,目前已經不使用,以下3個是函數通過driver註冊I2c core,通過遍歷I2C bus的設備,匹配後創建adapter以及i2c client*/
	int (*detect)(struct i2c_client *, struct i2c_board_info *);
	const unsigned short *address_list;
	struct list_head clients;
};
struct i2c_client {
	unsigned short flags;		/* div., see below		*/
	unsigned short addr;		/* chip address - NOTE: 7bit	*/
					/* addresses are stored in the	*/
					/* _LOWER_ 7 bits		*/
	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		*/
	struct list_head detected;
};
struct i2c_board_info {
	char		type[I2C_NAME_SIZE];
	unsigned short	flags;
	unsigned short	addr;
	void		*platform_data;
	struct dev_archdata	*archdata;
	struct device_node *of_node;
	struct acpi_dev_node acpi_node;
	int		irq;
};
struct i2c_algorithm {
	/* If an adapter algorithm can't do I2C-level access, set master_xfer
	   to NULL. If an adapter algorithm can do SMBus access, set
	   smbus_xfer. If set to NULL, the SMBus protocol is simulated
	   using common I2C messages */
	/* master_xfer should return the number of messages successfully
	   processed, or a negative value on error */
	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);

	/* To determine what the adapter supports */
	u32 (*functionality) (struct i2c_adapter *);
};
```c
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	*/
	struct rt_mutex bus_lock;

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

	int nr;                             //I2C bus number
	char name[48];
	struct completion dev_released;

	struct mutex userspace_clients_lock;
        /*用戶空間的client設備,通過sysfs中adapter 中/sys/bus/i2c/devices/i2c-0 中的名字爲new_device 中的store新增i2c設備,並將其添加到對應的adapter中,*/
	struct list_head userspace_clients;

	struct i2c_bus_recovery_info *bus_recovery_info;
};

相關的API:
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
向I2C核心註冊一個i2C驅動(driver_register),將驅動掛載在I2C bus上,在/sys/bus/i2c/drivers生成一個目錄。 I2C bus上會調用match,match 返回1,表示match成功,後執行bus->probe ,隨後調用 driver->probe.

I2C驅動以及控制器編寫步驟

I2C 設備驅動編寫方法:
1.定義一個struct i2c_driver temp
2.賦值temp,賦值name,probe,remove,driver中的name,以及of_match_table(和device tree相關),如果沒有device tree,則賦值id_table,通過name來進行match,賦值driver中的pm的fops(建議),或者初始化i2c 的driversuspend或者resume
3.調用i2c_add_driver。
4.調用I2c_transfer(I2c msg);發送數據

CONFIG_PM_SLEEP 關於power manger

I2C 控制器驅動:

定義platform_driver xxx_i2c_driver
例如:

static struct platform_driver s3c24xx_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.id_table	= s3c24xx_driver_ids,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c-i2c",
		.pm	= S3C24XX_DEV_PM_OPS,
		.of_match_table = of_match_ptr(s3c24xx_i2c_match),  使用device Tree

	},
};

@2probe回調函數中,讀取設備樹I2C節點參數,初始化註冊一個I2C adapter

    i2c->adap.owner   = THIS_MODULE;
	i2c->adap.algo    = &s3c24xx_i2c_algorithm;           //賦值真正的傳輸
	i2c->adap.retries = 2;                                             //I2C 控制器傳輸retry此處
	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
	i2c->tx_setup     = 50;
@3註冊adapter

I2C DeviceTree

i2c1: i2c@400a0000 {
		/* ... master properties skipped ... */
		clock-frequency = <100000>;
               status = "okay";
		flash@50 {
			compatible = "atmel,24c256";
			reg = <0x50>;
		};

		pca9532: gpio@60 {
			compatible = "nxp,pca9532";
			gpio-controller;
			#gpio-cells = <2>;
			reg = <0x60>;
		};
	};

clock-frequency :i2c的時鐘頻率
reg:i2c的7bit addr
compatible:i2c 設備的name
status:狀態,okay表示使能對應的i2c

對於以上的節點:在三星以及rookchip平臺上會是以下的結果:

I2C 控制器驅動:platformdriver xxx_driver

xxx.driver中的driver中of_match_table的會匹配device tree中的I2C 節點compatible屬性.

xxx_driver中會註冊I2C adapter,adapter會申請I2C client,I2C client 中會將其對應的deviceTree中的子設備創建,一個I2C client對飲一個I2C 的從設備,將設備屬性與I2C driver進行匹配,然後綁定.

I2C Trace(從其它地方拷貝)

Add tracepoints into the I2C message transfer function to retrieve the message
sent or received. The following config options must be turned on to make use
of the facility:

CONFIG_FTRACE
CONFIG_ENABLE_DEFAULT_TRACERS

The I2C tracepoint can be enabled thusly:

echo 1 >/sys/kernel/debug/tracing/events/i2c/enable

and will dump messages that can be viewed in /sys/kernel/debug/tracing/trace
that look like:

... i2c_write: i2c-5 #0 a=044 f=0000 l=2 [02-14]
... i2c_read: i2c-5 #1 a=044 f=0001 l=4
... i2c_reply: i2c-5 #1 a=044 f=0001 l=4 [33-00-00-00]
... i2c_result: i2c-5 n=2 ret=2

formatted as:

i2c-<adapter-nr>
#<message-array-index>
a=<addr>
f=<flags>
l=<datalen>
n=<message-array-size>
ret=<result>
[<data>]

The operation is done between the i2c_write/i2c_read lines and the i2c_reply
and i2c_result lines so that if the hardware hangs, the trace buffer can be
consulted to determine the problematic operation.

The adapters to be traced can be selected by something like:

echo adapter_nr==1 >/sys/kernel/debug/tracing/events/i2c/filter

These changes are based on code from Steven Rostedt.

I2C-dev

I2C dev主要作用:可以使用應用層讀寫的方式,向對應的I2C bus上讀寫數據
具體實現:
文件中主要實現了對I2C bus上device add 以及del的監聽,通過bus_register_notify,當有設備掛載到I2C bus上時,會回調notify.notify中創建adapter的設備節點,主設備號是89,此設備號是i2C bus的編號,adapter-nr

@1申請字符設備,註冊I2C bus監聽
@2有I2C bus上的設備註冊,回調i2cdev_attach_adapter,
@3i2cdev_attach_adapter 中完成設備的註冊,在/dev下創建i2c-%d,%d是adapter->nr
@4通過Ictrl 配置I2C client 的從地址等參數
@5在對應的I2C adapter上發送數據

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