I2C总线相关_1

本文详细介绍了I2C总线的工作原理和技术细节,包括两线制时钟和数据信号的功能,芯片地址的确定方法,以及如何通过文件系统进行读写操作。深入探讨了I2C核心层函数如i2c_master_send和i2c_master_recv的实现,并解释了设备注册过程。
摘要由CSDN通过智能技术生成

关于I2C经验


I2C有两根线,

一根提供时钟(始终都是由主端提供的)

一根提供数据

先不说时序

先确定一个一个时钟 多少事件
一般是400khz

然后读 i2c的话

一般要确定芯片地址



i2C上可以挂很多东西

例如AD 时钟芯片  每个芯片都有一个地址

i2c在文件系统中表现为dev目录下的一个文件.调用相应的接口读就行了.

读的时候先确定地址

然后确定 芯片中的寄存器地址

然后就能读到 了 

device端

platform_device_register
struct platform_device hi_i2c0_device = {
	.name		= HI_I2C,
	.id		= 0,
	.resource	= hi_i2c0_resources,
	.num_resources	= ARRAY_SIZE(hi_i2c0_resources),
	.dev		= {
		.platform_data	= &hi_i2c0_platform_data,
	}
};

driver端

platform_driver_register

static struct platform_driver hi_i2c_driver = {
	.probe		= hi_i2c_probe,
	.remove		= hi_i2c_remove,
	.suspend	= hi_i2c_suspend,
	.resume		= hi_i2c_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= HI_I2C,
	},
};



##I2C核心层

这是其他驱动里面调用的函数,在驱动里面并没有声明.
i2c_master_send
i2c_master_recv
/*drivers/i2c/i2c-core.c*/

/**
 * i2c_master_send - issue a single I2C message in master transmit mode
 * @client: Handle to slave device
 * @buf: Data that will be written to the slave                                                                                                                      
 * @count: How many bytes to write, must be less than 64k since msg.len is u16
 *
 * Returns negative errno, or else the number of bytes written.
 */
int i2c_master_send(const struct i2c_client *client, const char *buf, int count)
{
    int ret; 
    struct i2c_adapter *adap = client->adapter;
    struct i2c_msg msg; 

    msg.addr = client->addr;
#ifdef CONFIG_HI_I2C
    msg.flags = client->flags;
#else
    msg.flags = client->flags & I2C_M_TEN;
#endif
    msg.len = count;
    msg.buf = (char *)buf;

    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; 
}
EXPORT_SYMBOL(i2c_master_send);

/**
 * i2c_master_recv - issue a single I2C message in master receive mode
 * @client: Handle to slave device
 * @buf: Where to store data read from slave
 * @count: How many bytes to read, must be less than 64k since msg.len is u16
 *
 * Returns negative errno, or else the number of bytes read.
 */
int i2c_master_recv(const struct i2c_client *client, char *buf, int count)
{
    struct i2c_adapter *adap = client->adapter;
    struct i2c_msg msg;
    int ret;

    msg.addr = client->addr;
#ifdef CONFIG_HI_I2C
    msg.flags = client->flags;
#else
    msg.flags = client->flags & I2C_M_TEN;
#endif
    msg.flags |= I2C_M_RD;
    msg.len = count;
    msg.buf = buf;

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

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


//驱动中的const struct i2c_client *client参数用
i2c_new_device  i2c_get_adapter 函数来定义,两个函数在i2c-core.c中
//i2c_master_send i2c_master_recv 函数向下调用 i2c_transfer

/**
 * i2c_transfer - execute a single or combined I2C message
 * @adap: Handle to I2C bus
 * @msgs: One or more messages to execute before STOP is issued to
 *	terminate the operation; each message begins with a START.
 * @num: Number of messages to be executed.
 *
 * Returns negative errno, else the number of messages executed.
 *
 * Note that there is no requirement that each message be sent to
 * the same slave address, although that is the most common model.
 */
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	int ret;

	/* 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 = i2c_trylock_adapter(adap);
			if (!ret)
				/* I2C activity is ongoing. */
				return -EAGAIN;
		} else {
			i2c_lock_adapter(adap);
		}

		ret = __i2c_transfer(adap, msgs, num);
		i2c_unlock_adapter(adap);

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

//这里面调用client里面的 adapter,锁,并解锁,并调用__i2c_transfer
/**
 * __i2c_transfer - unlocked flavor of i2c_transfer
 * @adap: Handle to I2C bus
 * @msgs: One or more messages to execute before STOP is issued to
 *	terminate the operation; each message begins with a START.
 * @num: Number of messages to be executed.
 *
 * Returns negative errno, else the number of messages executed.
 *
 * Adapter lock must be held when calling this function. No debug logging
 * takes place. adap->algo->master_xfer existence isn't checked.
 */
int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
	unsigned long orig_jiffies;
	int ret, try;

	/* 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;
	}
	return ret;
}
EXPORT_SYMBOL(__i2c_transfer);
//这里面调用adapter的adap->algo->master_xfer,这个东西在哪里?
/*
 * The following structs are for those who like to implement new bus drivers:
 * i2c_algorithm is the interface to a class of hardware solutions which can
 * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
 * to name two of the most common.
 */
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 *);
};

//这个东西是结构体里面的一个成员

//之前说过
//驱动中的const struct i2c_client *client参数用
//i2c_new_device  i2c_get_adapter 函数来定义,两个函数在i2c-core.c中
//首先调用 i2c_get_adapter 来获取一个 i2c_adapter
//这个函数是用来获取一个i2c总线
struct i2c_adapter *i2c_get_adapter(int nr)
{
	struct i2c_adapter *adapter;
	mutex_lock(&core_lock);
	adapter = idr_find(&i2c_adapter_idr, nr);
	if (adapter && !try_module_get(adapter->owner))
		adapter = NULL;
  
	mutex_unlock(&core_lock);
	return adapter;
}
EXPORT_SYMBOL(i2c_get_adapter);
//可见i2c_get_adapter 函数调用了idr_find
/**
 * idr_find - return pointer for given id
 * @idr: idr handle
 * @id: lookup key
 *
 * Return the pointer given the id it has been registered with.  A %NULL
 * return indicates that @id is not valid or you passed %NULL in
 * idr_get_new().
 *
 * This function can be called under rcu_read_lock(), given that the leaf
 * pointers lifetimes are correctly managed.
 */
static inline void *idr_find(struct idr *idr, int id)
{
	struct idr_layer *hint = rcu_dereference_raw(idr->hint);

	if (hint && (id & ~IDR_MASK) == hint->prefix)
		return rcu_dereference_raw(hint->ary[id & IDR_MASK]);

	return idr_find_slowpath(idr, id);
}

//可见 idr_find 函数调用了 idr_find_slowpath
void *idr_find_slowpath(struct idr *idp, int id)
{
	int n;
	struct idr_layer *p;

	if (id < 0)
		return NULL;

	p = rcu_dereference_raw(idp->top);
	if (!p)
		return NULL;
	n = (p->layer+1) * IDR_BITS;

	if (id > idr_max(p->layer + 1))
		return NULL;
	BUG_ON(n == 0);

	while (n > 0 && p) {
		n -= IDR_BITS;
		BUG_ON(n != p->layer*IDR_BITS);
		p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]);
	}
	return((void *)p);
}
EXPORT_SYMBOL(idr_find_slowpath);


//这个函数是在i2c总线上创建一个设备
/**
 * i2c_new_device - instantiate an i2c device
 * @adap: the adapter managing the device
 * @info: describes one I2C device; bus_num is ignored
 * Context: can sleep
 *
 * Create an i2c device. Binding is handled through driver model
 * probe()/remove() methods.  A driver may be bound to this device when we
 * return from this function, or any later moment (e.g. maybe hotplugging will
 * load the driver module).  This call is not appropriate for use by mainboard
 * initialization logic, which usually runs during an arch_initcall() long
 * before any i2c_adapter could exist.
 *
 * This returns the new i2c client, which may be saved for later use with
 * i2c_unregister_device(); or NULL to indicate an error.
 */
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
	struct i2c_client	*client;
	int			status;

	client = kzalloc(sizeof *client, GFP_KERNEL);
	if (!client)
		return NULL;

	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;
	client->dev.of_node = info->of_node;
	ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);

	/* For 10-bit clients, add an arbitrary offset to avoid collisions */
	dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
		     client->addr | ((client->flags & I2C_CLIENT_TEN)
				     ? 0xa000 : 0));
	status = device_register(&client->dev);
	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;
}
EXPORT_SYMBOL_GPL(i2c_new_device);
//可见,这里绑定了之前申请的总线和新创建的设备.
//新设备的adapter是从之前申请总线返回的东西

匹配

//找了很长时间,懒得找了,从驱动到i2c的匹配估计是匹配到了drivers/i2c/busses/目录下的具体文件中的probe函数中创建的 adap 结构体
//其中adap->algo被填充为该文件中的
static const struct i2c_algorithm hi_i2c_algo = {
    .master_xfer    = hi_i2c_xfer,
    .functionality  = hi_i2c_func,
};
//那么xfer 也就有了
//hi_i2c_xfer 根据参数 调用 hi_i2c_read 和 hi_i2c_write
//hi_i2c_read hi_i2c_write 实现了时序.

//好像不是这样子,这样子找不到匹配的路径
//应该是创建设备后匹配的.
//i2c_new_device 函数的第一个参数为总线,第二个参数为device.
static struct i2c_board_info hi_info =
{
    I2C_BOARD_INFO("nvp6124", 0x60),
};
//device上有板子的信息

//在系统中,本来存在drivers/i2c/busses/的文件中
//被内建入内核,创建了一个adapter,相当于一个车轮子.
//这个车轮子在哪个总线上已经被adap->class = platform_info->i2c_class;定义
//但是没看到是怎么匹配的?

//当我在总线上创建设备的时候,我相当于注册了一个车架子.这是系统去找合适的车轮子.
//怎么找的?
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,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);

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

//我好像没看到driver端
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值