一、i2c驱动核心层分析

i2c驱动核心层主要为设备驱动层提供设备注册、通信、管理等接口,同时连接i2c控制器驱动。这里首先分析i2c子系统中比较重要的几个结构体:

1、driver

struct i2c_driver {
	unsigned int class;   	// 驱动支持的设备类型,如传感器、eeprom等

        /* Notifies the driver that a new bus has appeared or is about to be
	 * removed. You should avoid using this if you can, it will probably
	 * be removed in a near future.
	 */
	int (*attach_adapter)(struct i2c_adapter *);    // 旧版探测函数
	int (*detach_adapter)(struct i2c_adapter *);
	/* 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 *);
	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;             // 驱动模型
	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;      // 驱动支持的设备地址,传递给detect函数
	struct list_head clients;                // 驱动节点
};

这个结构体代表了一个i2c设备驱动,其中class代表i2c器件的类型,attach_adapter和detach_adapter代表从总线上添加或者删除设备,probe和remove用于绑定和解除绑定,alert用于SMBus,driver是设备的驱动模型,id_tabel代表驱动所支持设备的信息,detect用于设备探测,address_list传递给detect,clients代表我们创建的客户端。 

2、device

struct i2c_client {
	unsigned short flags;		    // 设备标志
	unsigned short addr;		    // 设备地址-7位
	char name[I2C_NAME_SIZE];       // 设备名称
	struct i2c_adapter *adapter;	// 设备所属的适配器
	struct i2c_driver *driver;	    // 设备所用的驱动
	struct device dev;		        // 设备模型
	int irq;			            // 设备可能会用到的中断号
	struct list_head detected;
};

该结构体代表一个i2c从设备,flags指定需要的特殊处理方式,addr是i2c设备的7位地址值,name是i2c设备名称,adapter为设备所属的适配器,driver为此设备的驱动程序,dev为设备的设备模型,irq为设备可能会用到的中断号。

struct i2c_board_info {
	char		type[I2C_NAME_SIZE];        // 设备名称
	unsigned short	flags;                  // 设备标志,如读取标志、十位地址位等
	unsigned short	addr;                   // 设备地址
	void		*platform_data;             // 设备私有数据
	struct dev_archdata	*archdata;
#ifdef CONFIG_OF
	struct device_node *of_node;
#endif
	int		irq;                            // 设备采用的中断号
};

这个结构体通常用于创建i2c设备,type为设备名称,platform_data为platform总线信息。通常采用如下方式注册i2c设备: 

static struct i2c_board_info __initdata i2c_devices0[]= {
       #ifdefined(CONFIG_REGULATOR_AXP192)
       {
              I2C_BOARD_INFO("axp192",0x34),
              .irq           = PMIC_IRQ,
              .platform_data= &axp192_info,
       },
       #endif
};

该数组包含一个通道上所有设备的信息,然后通过i2c_register_board_info函数注册该通道上所有设备。

int __init i2c_register_board_info(int busnum,
	struct i2c_board_info const *info, unsigned len)
{
	int status;

	down_write(&__i2c_board_lock);

	/* dynamic bus numbers will be assigned after the last static one */
	if (busnum >= __i2c_first_dynamic_bus_num)
		__i2c_first_dynamic_bus_num = busnum + 1;

	for (status = 0; len; len--, info++) {
		struct i2c_devinfo	*devinfo;

		devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
		if (!devinfo) {
			pr_debug("i2c-core: can't register boardinfo!\n");
			status = -ENOMEM;
			break;
		}

		devinfo->busnum = busnum;
		devinfo->board_info = *info;
		list_add_tail(&devinfo->list, &__i2c_board_list);  // 将设备依次添加到全局设备链表中
	}

	up_write(&__i2c_board_lock);

	return status;
}

其中busnum指定通道,info指定设备信息,len指定设备数量,该函数将设备依次添加到全局设备链表__i2c_board_list中。链表节点devinfo中有设备信息以及设备所连接的通道。

struct i2c_devinfo {
	struct list_head	list;              // 设备节点
	int			busnum;                    // i2c通道
	struct i2c_board_info	board_info;    // 设备信息
};

函数的调用方式如下:

i2c_register_board_info(0, i2c_devices0, ARRAY_SIZE(i2c_devices0));

3、adapter

struct i2c_adapter {
	struct module *owner;
	unsigned int id;
	unsigned int class;		               // 适配器支持的类型
	const struct i2c_algorithm *algo;      // 适配器通信的方法
	void *algo_data;                       // 适配器私有数据

	/* data fields that are valid for all devices	*/
	struct rt_mutex bus_lock;

	int timeout;			               // 超时时间
	int retries;                           // i2c超时重试次数
	struct device dev;		               // 设备模型
	int nr;                                // 适配器为i2c的第几通道
	char name[48];                         // 适配器名称
	struct completion dev_released;

	struct list_head userspace_clients;
};

i2c_adapter代表一个适配器,一个i2c通道就是一个适配器,algo指定该适配器的方法。 

4、algorithm

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

	/* 获取适配器支持的通信方式 */
	u32 (*functionality) (struct i2c_adapter *);
};

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	unsigned long orig_jiffies;
	int ret, try;

	/* REVISIT the fault reporting model here is weak:
	 *
	 *  - When we get an error after receiving N bytes from a slave,
	 *    there is no way to report "N".
	 *
	 *  - When we get a NAK after transmitting N bytes to a slave,
	 *    there is no way to report "N" ... or to let the master
	 *    continue executing the rest of this combined message, if
	 *    that's the appropriate response.
	 *
	 *  - When for example "num" is two and we successfully complete
	 *    the first message but get an error part way through the
	 *    second, it's unclear whether that should be reported as
	 *    one (discarding status on the second message) or errno
	 *    (discarding status on the first one).
	 */

	if (adap->algo->master_xfer) {
#ifdef DEBUG
		for (ret = 0; ret < num; ret++) {
			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
		}
#endif

		if (in_atomic() || irqs_disabled()) {
			ret = rt_mutex_trylock(&adap->bus_lock);
			if (!ret)
				/* I2C activity is ongoing. */
				return -EAGAIN;
		} else {
			rt_mutex_lock(&adap->bus_lock);
		}

		/* Retry automatically on arbitration loss */
		orig_jiffies = jiffies;
		for (ret = 0, try = 0; try <= adap->retries; try++) {
			ret = adap->algo->master_xfer(adap, msgs, num);    // 发送或者读取数据包
			if (ret != -EAGAIN)
				break;
			if (time_after(jiffies, orig_jiffies + adap->timeout))
				break;
		}
		rt_mutex_unlock(&adap->bus_lock);

		return ret;
	} else {
		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
		return -EOPNOTSUPP;
	}
}

i2c_algorithm结构体指定了i2c通信实现的方法。当需要发送或者接受i2c数据时就通过i2c_transfer实现对硬件的控制,该函数通常被封装成i2c_master_send以及i2c_master_recv供驱动程序调用。

int i2c_master_send(struct i2c_client *client, const char *buf, int count)
{
	int ret;
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;
    /* 填充msg */
	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.len = count;
	msg.buf = (char *)buf;
	/* S: telechips */
	msg.flags = (client->flags & I2C_M_MODE) | (client->flags & I2C_M_WR_RD);
	/* E: telechips */

	ret = i2c_transfer(adap, &msg, 1);

	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
	   transmitted, else error code. */
	return (ret == 1) ? count : ret;
}
int i2c_master_recv(struct i2c_client *client, char *buf, int count)
{
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;
	int ret;

	msg.addr = client->addr;
	msg.flags = client->flags & I2C_M_TEN;
	msg.flags |= I2C_M_RD;
	msg.len = count;
	msg.buf = buf;
	/* S: telechips */
	msg.flags |= (client->flags & I2C_M_MODE);
	/* E: telechips */

	ret = i2c_transfer(adap, &msg, 1);

	/* If everything went ok (i.e. 1 msg transmitted), return #bytes
	   transmitted, else error code. */
	return (ret == 1) ? count : ret;
}

struct i2c_msg {
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
/* Telechips */
#define I2C_M_MODE   0x0040  /* if slave is TCC DxB chip */
#define I2C_M_WR_RD  0x0080  /* if write->read operation */
#define I2C_M_WM899x_CODEC  0x0100  /* if slave is wm899x codec */

	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
};

i2c_msg为i2c通信的数据包。

5、bus

下面我们来分析i2c总线的注册过程:

static int __init i2c_init(void)
{
	int retval;
    /* 注册i2c总线 */
	retval = bus_register(&i2c_bus_type);
	if (retval)
		return retval;
#ifdef CONFIG_I2C_COMPAT
	i2c_adapter_compat_class = class_compat_register("i2c-adapter");
	if (!i2c_adapter_compat_class) {
		retval = -ENOMEM;
		goto bus_err;
	}
#endif
	retval = i2c_add_driver(&dummy_driver);
	if (retval)
		goto class_err;
	return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
	class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
	bus_unregister(&i2c_bus_type);
	return retval;
}

postcore_initcall(i2c_init);    // 此处采用postcore_initcall调用i2c-bus注册

其中

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

static const struct dev_pm_ops i2c_device_pm_ops = {
	.suspend = i2c_device_pm_suspend,
	.resume = i2c_device_pm_resume,
	.freeze = i2c_device_pm_freeze,
	.thaw = i2c_device_pm_thaw,
	.poweroff = i2c_device_pm_poweroff,
	.restore = i2c_device_pm_restore,
	SET_RUNTIME_PM_OPS(
		pm_generic_runtime_suspend,
		pm_generic_runtime_resume,
		pm_generic_runtime_idle
	)
};
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
						const struct i2c_client *client)
{
	while (id->name[0]) {
		if (strcmp(client->name, id->name) == 0)
			return id;
		id++;
	}
	return NULL;
}

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;

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

i2c设备和驱动的匹配函数。 

static int i2c_device_probe(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;

	if (!client)
		return 0;

	driver = to_i2c_driver(dev->driver);
	if (!driver->probe || !driver->id_table)
		return -ENODEV;
	client->driver = driver;
	if (!device_can_wakeup(&client->dev))
		device_init_wakeup(&client->dev,
					client->flags & I2C_CLIENT_WAKE);
	dev_dbg(dev, "probe\n");

	status = driver->probe(client, i2c_match_id(driver->id_table, client));
	if (status) {
		client->driver = NULL;
		i2c_set_clientdata(client, NULL);
	}
	return status;
}

该函数最终调用driver->probe进入设备驱动。

static int i2c_device_remove(struct device *dev)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int			status;

	if (!client || !dev->driver)
		return 0;

	driver = to_i2c_driver(dev->driver);
	if (driver->remove) {
		dev_dbg(dev, "remove\n");
		status = driver->remove(client);
	} else {
		dev->driver = NULL;
		status = 0;
	}
	if (status == 0) {
		client->driver = NULL;
		i2c_set_clientdata(client, NULL);
	}
	return status;
}

该函数最终调用driver-> remove进入设备驱动。

static inline int i2c_add_driver(struct i2c_driver *driver)
{
	return i2c_register_driver(THIS_MODULE, driver);
}

6、i2c-driver注册流程。

int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
	int res;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p)))
		return -EAGAIN;

	/* add the driver to the list of i2c drivers in the driver core */
	driver->driver.owner = owner;
	driver->driver.bus = &i2c_bus_type;

	/* When registration returns, the driver core
	 * will have called probe() for all matching-but-unbound devices.
	 */
	res = driver_register(&driver->driver);    // 注册driver
	if (res)
		return res;

	pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

	INIT_LIST_HEAD(&driver->clients);
	/* Walk the adapters that are already present */
	mutex_lock(&core_lock);
	bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
	mutex_unlock(&core_lock);

	return 0;
}

static int __process_new_driver(struct device *dev, void *data)
{
	if (dev->type != &i2c_adapter_type)
		return 0;
	return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}

其中bus_for_each_dev搜寻该总线上所有设备并调用__process_new_driver,设备已经在板级初始化程序中创建和注册。

static int i2c_do_add_adapter(struct i2c_driver *driver,
			      struct i2c_adapter *adap)
{
	/* Detect supported devices on that bus, and instantiate them */
	i2c_detect(adap, driver);

	/* Let legacy drivers scan this bus for matching devices */
	if (driver->attach_adapter) {
		/* We ignore the return code; if it fails, too bad */
		driver->attach_adapter(adap);
	}
	return 0;
}
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{
	const unsigned short *address_list;
	struct i2c_client *temp_client;
	int i, err = 0;
	int adap_id = i2c_adapter_id(adapter);    // 获取device的适配器连接的哪个i2c通道

	address_list = driver->address_list;      // 获取driver中的地址列表
	if (!driver->detect || !address_list)
		return 0;

	/* Set up a temporary client to help detect callback */
	temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);  // 创建一个临时i2c设备
	if (!temp_client)
		return -ENOMEM;
	temp_client->adapter = adapter;           // 初始化temp_client

	/* 判断device和driver中的设备是否一致 */
	if (!(adapter->class & driver->class)) 
		goto exit_free;

	/* 判断适配器是否支持探测 */
	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
		if (address_list[0] == I2C_CLIENT_END)
			goto exit_free;

		dev_warn(&adapter->dev, "Probing not supported\n");
		err = -EOPNOTSUPP;
		goto exit_free;
	}

	for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {// 枚举driver地址列表中的地址
		dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
			"addr 0x%02x\n", adap_id, address_list[i]);
		temp_client->addr = address_list[i];
		err = i2c_detect_address(temp_client, driver);      // 开始探测
		if (err)
			goto exit_free;
	}

 exit_free:
	kfree(temp_client);
	return err;
}
static int i2c_detect_address(struct i2c_client *temp_client,
			      struct i2c_driver *driver)
{
	struct i2c_board_info info;
	struct i2c_adapter *adapter = temp_client->adapter;
	int addr = temp_client->addr;
	int err;

	/* Make sure the address is valid */
	err = i2c_check_addr_validity(addr);       // 检测地址是否有效
	if (err) {
		dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
			 addr);
		return err;
	}

	/* Skip if already in use */
	if (i2c_check_addr_busy(adapter, addr))    // 检测地址是否被占用
		return 0;

	/* Make sure there is something at this address */
	if (!i2c_default_probe(adapter, addr))     // 探测设备是否存在
		return 0;

	/* Finally call the custom detection function */
	memset(&info, 0, sizeof(struct i2c_board_info));
	info.addr = addr;
	err = driver->detect(temp_client, &info);  // 调用平台函数探测设备并填充info
	if (err) {
		/* -ENODEV is returned if the detection fails. We catch it
		   here as this isn't an error. */
		return err == -ENODEV ? 0 : err;
	}

	/* Consistency check */
	if (info.type[0] == '\0') {                // 设备名为空
		dev_err(&adapter->dev, "%s detection function provided "
			"no name for 0x%x\n", driver->driver.name,
			addr);
	} else {
		struct i2c_client *client;

		/* Detection succeeded, instantiate the device */
		dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
			info.type, info.addr);
		client = i2c_new_device(adapter, &info);
		if (client)
			list_add_tail(&client->detected, &driver->clients);//将client添加到驱动程序链表
		else
			dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
				info.type, info.addr);
	}
	return 0;
}
将刚创建设备的client->detected添加到驱动程序链表里面。

static int i2c_check_addr_validity(unsigned short addr)
{
	/*
	 * Reserved addresses per I2C specification:
	 *  0x00       General call address / START byte
	 *  0x01       CBUS address
	 *  0x02       Reserved for different bus format
	 *  0x03       Reserved for future purposes
	 *  0x04-0x07  Hs-mode master code
	 *  0x78-0x7b  10-bit slave addressing
	 *  0x7c-0x7f  Reserved for future purposes
	 */
	if (addr < 0x08 || addr > 0x77)
		return -EINVAL;
	return 0;
}

该函数检测i2c地址是否有效。

static int __i2c_check_addr_busy(struct device *dev, void *addrp)
{
	struct i2c_client	*client = i2c_verify_client(dev);
	int			addr = *(int *)addrp;

	if (client && client->addr == addr)
		return -EBUSY;
	return 0;
}

static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
{
	return device_for_each_child(&adapter->dev, &addr,__i2c_check_addr_busy);
}

检测地址是否已经被占用。

static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr)
{
	int err;
	union i2c_smbus_data dummy;

#ifdef CONFIG_X86
	if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON)
	 && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA))
		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
				     I2C_SMBUS_BYTE_DATA, &dummy);
	else
#endif
	if ((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50
	 || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
				     I2C_SMBUS_BYTE, &dummy);
	else
		err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
				     I2C_SMBUS_QUICK, NULL);

	return err >= 0;
}

s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
		   char read_write, u8 command, int protocol,
		   union i2c_smbus_data *data)
{
	unsigned long orig_jiffies;
	int try;
	s32 res;

	flags &= I2C_M_TEN | I2C_CLIENT_PEC;

	if (adapter->algo->smbus_xfer) {
		rt_mutex_lock(&adapter->bus_lock);

		/* Retry automatically on arbitration loss */
		orig_jiffies = jiffies;
		for (res = 0, try = 0; try <= adapter->retries; try++) {
			res = adapter->algo->smbus_xfer(adapter, addr, flags,
							read_write, command,
							protocol, data);
			if (res != -EAGAIN)
				break;
			if (time_after(jiffies,
				       orig_jiffies + adapter->timeout))
				break;
		}
		rt_mutex_unlock(&adapter->bus_lock);
	} else    // 如果不存在物理上的SMBus,则采用i2c模拟
		res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
					      command, protocol, data);

	return res;
}

i2c_default_probe检测该设备是否存在。

struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
	struct i2c_client	*client;
	int			status;
    /* 创建client */
	client = kzalloc(sizeof *client, GFP_KERNEL);
	if (!client)
		return NULL;
    /* 填充client */
	client->adapter = adap;

	client->dev.platform_data = info->platform_data;

	if (info->archdata)
		client->dev.archdata = *info->archdata;

	client->flags = info->flags;
	client->addr = info->addr;
	client->irq = info->irq;

	strlcpy(client->name, info->type, sizeof(client->name));

	/* Check for address validity */
	status = i2c_check_client_addr_validity(client);
	if (status) {
		dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
			client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
		goto out_err_silent;
	}

	/* Check for address business */
	status = i2c_check_addr_busy(adap, client->addr);
	if (status)
		goto out_err;

	client->dev.parent = &client->adapter->dev;
	client->dev.bus = &i2c_bus_type;
	client->dev.type = &i2c_client_type;
#ifdef CONFIG_OF
	client->dev.of_node = info->of_node;
#endif
    /* 根据设备占用的i2c通道和地址命名设备 */
	dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
		     client->addr);
	status = device_register(&client->dev);    // 注册device
	if (status)
		goto out_err;

	dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
		client->name, dev_name(&client->dev));

	return client;

out_err:
	dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
		"(%d)\n", client->name, client->addr, status);
out_err_silent:
	kfree(client);
	return NULL;
}

首先搜寻总线上所有的设备 -> 根据驱动中的设备地址列表探测设备是否存在 -> 如果存在则创建一个client。

7、i2c-adapter注册流程

int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
	int	id;
	int	status;

	if (adap->nr & ~MAX_ID_MASK)
		return -EINVAL;

retry:
	if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
		return -ENOMEM;

	mutex_lock(&core_lock);
	/* "above" here means "above or equal to", sigh;
	 * we need the "equal to" result to force the result
	 */
	status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
	if (status == 0 && id != adap->nr) {
		status = -EBUSY;
		idr_remove(&i2c_adapter_idr, id);
	}
	mutex_unlock(&core_lock);
	if (status == -EAGAIN)
		goto retry;

	if (status == 0)
		status = i2c_register_adapter(adap);    // 调用注册函数
	return status;
}

函数的功能是注册一个适配器,该适配器通道已定义,如果要注册一个动态通道号的适配器则采用i2c_add_adapter函数。

static int i2c_register_adapter(struct i2c_adapter *adap)
{
	int res = 0, dummy;

	/* Can't register until after driver model init */
	if (unlikely(WARN_ON(!i2c_bus_type.p))) {
		res = -EAGAIN;
		goto out_list;
	}

	rt_mutex_init(&adap->bus_lock);
	INIT_LIST_HEAD(&adap->userspace_clients);

	/* 如果没有设置超时时间则设置为1秒 */
	if (adap->timeout == 0)
		adap->timeout = HZ;

	dev_set_name(&adap->dev, "i2c-%d", adap->nr);    // 设置适配器名称
	adap->dev.bus = &i2c_bus_type;                   // 设置适配器所属总线
	adap->dev.type = &i2c_adapter_type;              // 设置适配器设备类型
	res = device_register(&adap->dev);               // 注册dev
	if (res)
		goto out_list;

	dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

#ifdef CONFIG_I2C_COMPAT
	res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
				       adap->dev.parent);
	if (res)
		dev_warn(&adap->dev,
			 "Failed to create compatibility class link\n");
#endif

	/* create pre-declared device nodes */
	if (adap->nr < __i2c_first_dynamic_bus_num)
		i2c_scan_static_board_info(adap);

	/* Notify drivers */
	mutex_lock(&core_lock);
	dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,  // 遍历总线上的驱动程序
				 __process_new_adapter);                 // 调用该函数
	mutex_unlock(&core_lock);

	return 0;

out_list:
	mutex_lock(&core_lock);
	idr_remove(&i2c_adapter_idr, adap->nr);
	mutex_unlock(&core_lock);
	return res;
}
static int __process_new_adapter(struct device_driver *d, void *data)
{
	return i2c_do_add_adapter(to_i2c_driver(d), data);    // 转到i2c_do_add_adapter
}

二、i2c控制器驱动分析

控制器层驱动程序主要初始化i2c控制器,实现通信方法。

static struct platform_driver tcc_i2c_driver = {
	.probe			= tcc_i2c_probe,
	.remove			= tcc_i2c_remove,
	.suspend		= tcc_i2c_suspend_late,
	.resume			= tcc_i2c_resume_early,
	.driver			= {
		.owner		= THIS_MODULE,
		.name		= "tcc-i2c",
	},
};

static int __init tcc_i2c_adap_init(void)
{
    return platform_driver_register(&tcc_i2c_driver);
}

subsys_initcall(tcc_i2c_adap_init);    // 此处采用subsys_initcall调用i2c子系统初始化函数
static int tcc_i2c_probe(struct platform_device *pdev)
{
	int i, ret;
	struct tcc_i2c *i2c;
    struct tcc_i2c_platform_data *tcc_platform_data = pdev->dev.platform_data;//设备资源
	struct resource *resource[I2C_NUM_OF_CH];

	i2c = kzalloc(sizeof(struct tcc_i2c) * I2C_NUM_OF_CH, GFP_KERNEL);
	if (!i2c) {
		ret = -ENOMEM;
		goto err_nockl;
	}

	for (i = 0; i < I2C_NUM_OF_CH; i++) {      // 初始化每个通道
		resource[i] = platform_get_resource(pdev, IORESOURCE_IO, i);
		if (!resource[i]) {
            printk("i2c%d: no io resource? (ch%d)\n", pdev->id, i);
			dev_err(&pdev->dev, "no io resource? (ch%d)\n", i);
			ret = -ENODEV;
			goto err_io;
		}

		i2c[i].adap.owner = THIS_MODULE;
		i2c[i].adap.algo = &tcc_i2c_algorithm;  // 通信方法
		i2c[i].adap.retries = 2;                // 超时后重复尝试次数
		sprintf(i2c[i].adap.name, "%s-ch%d",pdev->name, i);    // 初始化适配器名称

		spin_lock_init(&i2c[i].lock);
		init_waitqueue_head(&i2c[i].wait);

		i2c[i].core     = pdev->id;             // 编号
		i2c[i].ch       = i;                    // 适配器通道
		i2c[i].regs     = (volatile struct tcc_i2c_regs *) IO_ADDRESS(resource[i]->start);                                        // 设置寄存器起始地址
        i2c[i].IRQSTR   = resource[i]->end;
        i2c[i].smu_i2c_flag  = tcc_platform_data->smu_i2c_flag;      // 设置标志位
        i2c[i].i2c_clk_rate  = tcc_platform_data->i2c_ch_clk_rate[i];// 设置i2c信号时钟频率
        i2c[i].core_clk_rate = tcc_platform_data->core_clk_rate;     // 设置i2c控制器频率
        memcpy(i2c[i].core_clk_name, tcc_platform_data->core_clk_name, sizeof(tcc_platform_data->core_clk_name));

        /* Set GPIO and Enable Clock */
		if(tcc_i2c_init(i2c + i) < 0) {
            goto err_io;
        }

		i2c[i].adap.algo_data = i2c + i;
		i2c[i].adap.dev.parent = &pdev->dev;
        #if 0
        #define I2C_CLASS_HWMON		(1<<0)	/* lm_sensors, ... */
        #define I2C_CLASS_TV_ANALOG	(1<<1)	/* bttv + friends */
        #define I2C_CLASS_TV_DIGITAL	(1<<2)	/* dvb cards */
        #define I2C_CLASS_DDC		(1<<3)	/* DDC bus on graphics adapters */
        #define I2C_CLASS_SPD		(1<<7)	/* SPD EEPROMs and similar */
        #endif
		i2c[i].adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;    // 设置适配支持的设备类型
		i2c[i].adap.nr = pdev->id * I2C_NUM_OF_CH + i;

		ret = i2c_add_numbered_adapter(&i2c[i].adap);           // 注册适配器
		if (ret < 0) {
			printk("%s: Failed to add bus\n", i2c[i].adap.name);
			for (i--; i >= 0; i--)
				i2c_del_adapter(&i2c[i].adap);
			goto err_clk;
		}
	}

	platform_set_drvdata(pdev, i2c);

	return 0;

err_clk:
    printk("~~~~~~ %s() err_clk\n", __func__);
	//TODO: I2C peri bus disable
	for(i = 0;i < I2C_NUM_OF_CH;i++) {
    	if(i2c[i].pclk != NULL) {
            clk_disable(i2c[i].pclk);
            clk_put(i2c[i].pclk);
            i2c[i].pclk = NULL;
        }
    }
err_io:
    printk("~~~~~~ %s() err_io\n", __func__);
	kfree(i2c);
err_nockl:
    printk("~~~~~~ %s() err_nock1\n", __func__);
	return ret;
}
static void tcc_i2c_message_start(struct tcc_i2c *i2c, struct i2c_msg *msg)
{
	unsigned int addr = (msg->addr & 0x7f) << 1;    // 获取设备地址,并左移1位

	if (msg->flags & I2C_M_RD)                      // 如果是读则设置最后一位为1
		addr |= 1;
	if (msg->flags & I2C_M_REV_DIR_ADDR)
		addr ^= 1;

	i2c->regs->TXR = addr;                          // 设置地址寄存器
	i2c->regs->CMD = Hw7 | Hw4;                     // 设置命令寄存器
}

static int wait_intr(struct tcc_i2c *i2c)
{
	unsigned long cnt = 0;

	if (!i2c->smu_i2c_flag) {
		while (!(tcc_readl(i2c->IRQSTR) & (i2c->ch?Hw1:Hw0))) {  // 等待应答信号
			cnt++;
			if (cnt > 100000) {
				printk("i2c-tcc: time out!  core%d ch%d\n", i2c->core, i2c->ch);
				return -1;
			}
		}
	} else {
		/* SMU_I2C wait */
		while (1) {
			cnt = i2c->regs->SR;
			if (!(cnt & Hw1)) break;
		}
		for (cnt = 0; cnt <15; cnt++);
	}

	return 0;
}

static int recv_i2c(struct tcc_i2c *i2c)
{
	int ret, i;
	dev_dbg(&i2c->adap.dev, "READ [%x][%d]\n", i2c->msg->addr, i2c->msg->len);

	tcc_i2c_message_start(i2c, i2c->msg);  // 开始通信,设置第一个字节值并开始发送

	ret = wait_intr(i2c);
	if (ret != 0)
		return ret;
	BITSET(i2c->regs->CMD, Hw0);	/* Clear a pending interrupt */

	for (i = 0; i < i2c->msg->len; i++) {
        if (i2c->msg->flags & I2C_M_WM899x_CODEC) { /* B090183 */    // 检测标志
            if (i == 0)
                i2c->regs->CMD = Hw5;
            else
                i2c->regs->CMD = Hw5 | Hw3;
        } else {
    		if (i == (i2c->msg->len - 1)) 
    			i2c->regs->CMD = Hw5 | Hw3;
    		else
    			i2c->regs->CMD = Hw5;
        }

		ret = wait_intr(i2c);
		if (ret != 0)
			return ret;
		BITSET(i2c->regs->CMD, Hw0);

		i2c->msg->buf[i] = (unsigned char) i2c->regs->RXR;
	}

	i2c->regs->CMD = Hw6;

	ret = wait_intr(i2c);
	if (ret != 0)
		return ret;
	BITSET(i2c->regs->CMD, Hw0);

	return 1;
}

static int send_i2c(struct tcc_i2c *i2c)
{
	int ret, i, no_stop = 0;
	dev_dbg(&i2c->adap.dev, "SEND [%x][%d]", i2c->msg->addr, i2c->msg->len);

	tcc_i2c_message_start(i2c, i2c->msg);

	ret = wait_intr(i2c);
	if (ret != 0)
		return ret;
	BITSET(i2c->regs->CMD, Hw0);	/* Clear a pending interrupt */

	for (i = 0; i < i2c->msg->len; i++) {
		i2c->regs->TXR = i2c->msg->buf[i];

        if(i2c->msg->flags == I2C_M_WM899x_CODEC)   /* B090183 */
            i2c->regs->CMD = Hw4 | Hw3;
        else
    		i2c->regs->CMD = Hw4;

		ret = wait_intr(i2c);
		if (ret != 0)
			return ret;
		BITSET(i2c->regs->CMD, Hw0);

		//i2c->msg->buf[i] = (unsigned char) i2c->regs->RXR;	//XXX
	}

	/*
	 *	Check no-stop operation condition (write -> read operation)
	 *	1. DxB
	 * 	2. msg_num == 2
	 */
	if (i2c->msg->flags & I2C_M_WR_RD)
		no_stop = 1;
	if (i2c->msg_num > 1)
		no_stop = 1;
	
	if (no_stop == 0) {
		i2c->regs->CMD = Hw6;
		ret = wait_intr(i2c);
		if (ret != 0)
			return ret;
	}
	BITSET(i2c->regs->CMD, Hw0);	/* Clear a pending interrupt */

	return 1;
}

/* tcc_i2c_doxfer
 *
 * this starts an i2c transfer
*/
static int tcc_i2c_doxfer(struct tcc_i2c *i2c, struct i2c_msg *msgs, int num)
{
	int ret, i;
	
	for (i = 0; i < num; i++) {    // 解析msg
		spin_lock_irq(&i2c->lock);
		i2c->msg 		= &msgs[i];
		i2c->msg->flags = msgs[i].flags;
		i2c->msg_num 	= num;
		i2c->msg_ptr 	= 0;
		i2c->msg_idx 	= 0;
		i2c->state = STATE_START;
		spin_unlock_irq(&i2c->lock);

		if (i2c->msg->flags & I2C_M_RD) {
			ret = recv_i2c(i2c);
			if (ret != 1)
				printk("recv_i2c failed\n");
		} else {
			ret = send_i2c(i2c);
			if (ret != 1)
				printk("send_i2c failed\n");
		}
	}
	
	return ret;
}

/* tcc_i2c_xfer
 *
 * first port of call from the i2c bus code when an message needs
 * transferring across the i2c bus.
*/
static int tcc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	struct tcc_i2c *i2c = (struct tcc_i2c *)adap->algo_data;
	int retry;
	int ret;

	for (retry = 0; retry < adap->retries; retry++) {
		
		ret = tcc_i2c_doxfer(i2c, msgs, num);

		if (ret == 1)
			return ret;

		dev_dbg(&i2c->adap.dev, "Retrying transmission (%d)\n", retry);

		udelay(100);
	}

	return -EREMOTEIO;
}

static u32 tcc_i2c_func(struct i2c_adapter *adap)
{
	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;  // 适配器拥有i2c和用i2c模拟SMBus的功能
}

/* i2c bus registration info */
static const struct i2c_algorithm tcc_i2c_algorithm = {
	.master_xfer	= tcc_i2c_xfer,
	.functionality	= tcc_i2c_func,
};
static int tcc_i2c_init(struct tcc_i2c *i2c)
{
	unsigned int prescale;
    volatile struct tcc_i2c_regs *i2c_reg = i2c->regs;

	if (!i2c->smu_i2c_flag) {
		/* I2C GPIO setting */
		tca_i2c_setgpio(i2c->core, i2c->ch);          // 设置io口功能

        /* I2C clock Enable */
        if(i2c->pclk == NULL) {
            i2c->pclk = clk_get(NULL, i2c->core_clk_name);
    		if (!i2c->pclk) {
    			dev_err(&i2c->dev, "can't get i2c clock\n");
    			return -1;
    		}
        }
		if(clk_enable(i2c->pclk) != 0) {
            dev_err(&i2c->dev, "can't do i2c clock enable\n");
            return -1;
        }

        /* Set i2c core clock to 4MHz */
        clk_set_rate(i2c->pclk, i2c->core_clk_rate);  // 设置控制器时钟频率

    	prescale = ((clk_get_rate(i2c->pclk) / 10) / (i2c->i2c_clk_rate * 5)) - 1;
    	writel(prescale, &i2c_reg->PRES);             // 初始化控制器
    	writel(Hw7 | Hw6 | HwZERO, &i2c_reg->CTRL);//start enable, stop enable, 8bit mode
    	writel(Hw0 | readl(&i2c_reg->CMD), &i2c_reg->CMD);//clear pending interrupt

        msleep(100);    // Why does it need ?
	} 
	else
	{
		/* SMU_I2C clock setting */
		tcc_writel(0x80000000, i2c->IRQSTR);

		i2c->regs->CTRL = 0;
		i2c->regs->PRES = 4;
		BITSET(i2c->regs->CTRL, Hw7|Hw6);
	}

    return 0;
}

三、i2c设备注册方法

常见有两种方式注册i2c设备,第一种在板级初始化程序中注册device(在第二小节已经分析过),然后在设备驱动程序中注册driver;第二种则同时在设备驱动程序中注册device和driver。

1、方式一:

static const struct i2c_device_id goodix_i2c_id[] = {
	{ "goodix_ts", 0 },
	{ }
};

static struct i2c_driver goodix_i2c_driver = {
	.probe		= goodix_i2c_probe,
	.remove		= goodix_i2c_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
	.suspend    = goodix_i2c_suspend,
	.resume     = goodix_i2c_resume,
#endif
	.driver = {
		.name = "goodix_ts",
		.owner = THIS_MODULE,
	},
	.id_table = goodix_i2c_id,
};

static int __init goodix_i2c_init(void)
{
	return i2c_add_driver(&goodix_i2c_driver);    // 注册已经注册了的device的driver
}
注册后i2c_device_probe将会执行,通过driver->probe调用刚注册的goodix_i2c_probe,传递的参数有两个:(client, i2c_match_id(driver->id_table, client))已经注册成功的client和id。

2、方式二

static const struct i2c_device_id it7260_i2c_id[] = {
    { "it7260_ts", 0, },
    { }
};

static struct i2c_driver it7260_i2c_driver = {
    .driver = {
        .name   = "it7260_ts",
        .owner  = THIS_MODULE,
    },
    .probe      = it7260_i2c_probe,
    .remove     = it7260_i2c_remove,
    .id_table   = it7260_i2c_id,
};

ret = i2c_add_driver(&it7260_i2c_driver);
首先在驱动程序的probe里面注册driver。

static int it7260_i2c_register(void)
{
    struct i2c_board_info info;
    struct i2c_adapter *adapter;
    struct i2c_client *client;

    memset(&info, 0, sizeof(struct i2c_board_info));    // 初始化i2c_board_info
    info.addr = TS_IT7260_I2C_ADDRESS;                  // i2c地址值
    strlcpy(info.type, "it7260_ts", I2C_NAME_SIZE);     // 设置设备名称
  
	adapter = i2c_get_adapter(0);                       // 获取i2c通道

    if (!adapter) 
    {
        ts_it7260_dbg(KERN_ERR "can't get i2c adapter 0 for it7260\n");
        return -ENODEV;
    }

    client = i2c_new_device(adapter, &info);            // 注册device并获取client
    i2c_put_adapter(adapter);
    if (!client) 
    {
        ts_it7260_dbg(KERN_ERR"can't add i2c device at 0x%x\n",(unsigned int)info.addr);
        return -ENODEV;
    }

    it7260_i2c_client = client;                         // 将client赋给全局变量

    return 0;
}

然后再调用it7260_i2c_register注册device。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐