Embedded linux IIC drive

1. Linux IIC-driven framework

Linux device driver and isolation, layered drivers, IIC drive frame is divided into two portions

  • IIC bus driver, that is, the SOC IIC controller driver, will drive adapter
  • IIC device driver, the device driver refers to the specific IIC

1.1 IIC bus driver

platform is a virtual bus, for there is no equipment to achieve, bus, device, driver of the bus frame, IIC not virtual, can be directly used bus bus. IIC bus driver has two important data structures: i2c_adapter, i2c_algorithm. i2c_adapter structure is defined as follows: include / linux / i2c.h

struct i2c_adapter {
	。。。
	const struct i2c_algortithm *algo;  /*总线访问算法*/
	。。。
}

By operation of the adapter device iic API functions in the i2c_algortithmstructural body, i2c_algortithmdefined in the include / linux / i2c.h

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);

	/* To determine what the adapter supports */
	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
};
  • master_xfer Data transfer is a data communication function, and completion equipment i2c i2c adapter
  • smbus_xfer data transfer function is smbus
    I2C bus driver, mainly i2c_adapter structure variables initialized, and the data transfer function provided master_xfer, after the system is completed by registering i2c_adapter, registration function is as follows:
int i2c_add_adapter(struct i2c_adapter *adapter) //使用动态总线号
int i2c_add_number_adapter(struct i2c_adapter *adap) //使用静态总线号
  • Parameters adapter / adap representation system adapter to be registered
  • 0 Success Return Value negative failed
    to delete IIC adapter function:
void i2c_del_adapter(struct i2c_adapter *adap);

1.2 IIC device driver

Focus is on two structures, i2c_client and i2c_driver.

  • i2c_client describes device information, inlcude / linux / i2c.h in
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;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};

Each detected IIC device will be assigned a i2c_client, the structures and devices correspondence

  • i2c_driver structure described device drivers include / linux / i2c.h
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 *);
	int (*remove)(struct i2c_client *);

	/* driver model interfaces that don't relate to enumeration  */
	void (*shutdown)(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;
	const struct i2c_device_id *id_table;

	/* Device detection callback for automatic device creation */
	int (*detect)(struct i2c_client *, struct i2c_board_info *);
	const unsigned short *address_list;
	struct list_head clients;
};

probe: IIC devices and driver execution probe function after successful match
device_driver: drive structure, if the tree by the device, provided of_match_table members, for compatibility properties
id_table: not using the device tree represents a device matching list

  • i2c_driver structure After construction, the need to register the linux kernel, registration function:
int i2c_register_driver(struct module *owner,struct i2c_driver *driver)

Parameters owner usually THIS_MODULE
Driver: need to register i2c_driver structure
Return Value 0 Success negative failure

  • IIC cancellation device drivers, function
void i2c_del_driver(struct i2c_driver *driver)

1.3 the drive device and the matching process

IIC device and driver matching IIC core is completed, drivers / i2c / i2c-core.c, provides some specific API functions and hardware-independent, i2c_adapter registration and cancellation function, i2c_driver register and unregister functions. IIC devices and driven by the I2C bus matches completed, the structure i2c_bus_type, defined in drivers / i2c / i2c-core.c

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};

and a driving device is i2c_device_match IIC match function, defined as follows

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;

	if (!client)
		return 0;

	/* Attempt an OF style match */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then ACPI style match */
	if (acpi_driver_match_device(dev, drv))
		return 1;

	driver = to_i2c_driver(drv);
	/* match on an id table if there is one */
	if (driver->id_table)
		return i2c_match_id(driver->id_table, client) != NULL;

	return 0;
}

of_driver_match_device: Device drivers and tree matching device, and compatible properties of_device_id compare the I2C compatible device node are equal, it is equal match
i2c_match_id: a conventional non-matching device tree, compares the device names and the name fields are equal i2c_device_id, it is equal match

2. I2C adapter driver analysis

I2C bus driver is actually driving the SOC I2C controllers, general SOC vendors have written. Find I2C1 control node I.MX6U in imx6ull.dtsi file,

i2c1: i2c@021a0000 {
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
	reg = <0x021a0000 0x4000>;
	interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_I2C1>;
	status = "disabled";
};

Drivers can then find the corresponding source code linux compatible property, I.MX6U I2C adapter drivers of the drivers / i2c / busser / i2c-imx.c

static struct platform_device_id imx_i2c_devtype[] = {
	{
		.name = "imx1-i2c",
		.driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
	}, {
		.name = "imx21-i2c",
		.driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
	}, {
		/* sentinel */
	}
};
MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);

static const struct of_device_id i2c_imx_dt_ids[] = {
	{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
	{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
	{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
。。。
static struct platform_driver i2c_imx_driver = {
	.probe = i2c_imx_probe,
	.remove = i2c_imx_remove,
	.driver	= {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
		.of_match_table = i2c_imx_dt_ids,
		.pm = IMX_I2C_PM,
	},
	.id_table	= imx_i2c_devtype,
};

static int __init i2c_adap_imx_init(void)
{
	return platform_driver_register(&i2c_imx_driver);
}
subsys_initcall(i2c_adap_imx_init);

static void __exit i2c_adap_imx_exit(void)
{
	platform_driver_unregister(&i2c_imx_driver);
}
module_exit(i2c_adap_imx_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Darius Augulis");
MODULE_DESCRIPTION("I2C adapter driver for IMX I2C bus");
MODULE_ALIAS("platform:" DRIVER_NAME);

As can be seen from the above standard I2C adapter driver is driving the platform, i2c_imx_probe function executes when the match is completed and a driving device, is the completion of the initialization I2C adapter.
The main function is to work i2c_imx_probe about two points:
①, initialization i2c_adapter, set i2c_algorithm to i2c_imx_algo, finally registered with the Linux kernel
i2c_adapter.
②, I2C1 initialization controller associated registers.

3. I2C device driver writing process

3.1 No device tree, I2C device description using

When unused device tree describing particular I2C device with i2c_board_info structure is defined as follows

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 fwnode_handle *fwnode;
	int		irq;
};

type: I2C device name
addr: I2C device address

3.2 device tree, I2C device description

In the case where the device tree, I2C device information added by creating a corresponding node, a child node created under the node i2c1, specific description of the information device i2c

3.3 I2C transceiver device data flow processing
Released four original articles · won praise 1 · views 152

Guess you like

Origin blog.csdn.net/m0_46291920/article/details/104370342
IIC