博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
I2C总线相关_1
阅读量:4285 次
发布时间:2019-05-27

本文共 12256 字,大约阅读时间需要 40 分钟。

关于I2C经验I2C有两根线,一根提供时钟(始终都是由主端提供的)一根提供数据先不说时序先确定一个一个时钟 多少事件一般是400khz然后读 i2c的话一般要确定芯片地址i2C上可以挂很多东西例如AD 时钟芯片  每个芯片都有一个地址i2c在文件系统中表现为dev目录下的一个文件.调用相应的接口读就行了.读的时候先确定地址然后确定 芯片中的寄存器地址然后就能读到 了

device端

platform_device_registerstruct 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_registerstatic 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_sendi2c_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端

转载地址:http://fvigi.baihongyu.com/

你可能感兴趣的文章
朴素贝叶斯分类器
查看>>
贝叶斯学习举例--学习分类文本
查看>>
hadoop HDFS原理基础知识
查看>>
数据挖掘十大算法----EM算法(最大期望算法)
查看>>
android StrictMode应用
查看>>
TabHost的两种使用方法
查看>>
Android---TextView属性详解
查看>>
K近邻算法基础:KD树的操作
查看>>
数据挖掘十大算法--K近邻算法
查看>>
android对话框(Dialog)的用法
查看>>
Android使用Application总结
查看>>
android启动第一个界面时即闪屏的核心代码(两种方式)
查看>>
数据挖掘十大经典算法(详解)
查看>>
数据挖掘十大算法--K-均值聚类算法
查看>>
java中常用的日期格式化(全)
查看>>
POI操作Excel导入和导出
查看>>
java的md5加密算法代码
查看>>
jdbc连接数据库
查看>>
Android开发四大组件概述
查看>>
Hadoop主要子项目介绍(Pig Zookeeper Hbase Hive Sqoop Avro Chukwa Cassandra )
查看>>