===============================
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/gdt_a20
===============================
I2c子系统将i2c控制器(i2c寄存器所在的那块电路)抽象出来,用adapter(适配器)这个结构来描述,可以说一个适配器就代表一条i2c总线,而挂接在i2c总线上的设备是用client这个结构体来表述,另外i2c_bus上的设备链表挂接的不单单是连接的这条i2c上的client,同样adapter也作为一个设备挂在其所在的i2c_bus,也就是说控制器和设备都作为i2c_bus上的设备连接在设备链表,他们用内嵌的device的type这个成员来区分,适配器的类型为i2c_adapter_type,client的类型为i2c_client_type。
一、i2c相关的描述结构
首先看一下i2c子系统给adapter定义的描述结构:
struct i2c_adapter { struct module *owner; unsigned int id; unsigned int class; // 适配器支持的类型,如传感器,eeprom等 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; //通信重复次数限定 /* * 内嵌的标准device,其中dev->type标识该设备 * 是个adapter,其值为i2c_adapter_type */ struct device dev; int nr; //适配器编号也是bus编号,第几条i2c总线 char name[48]; //名字 struct completion dev_released; struct mutex userspace_clients_lock; struct list_head userspace_clients; };
再来看一下client的描述结构:
struct i2c_client { unsigned short flags; //设备的标志,如唤醒标志等等 /* chip address - NOTE: 7bit */ /* addresses are stored in the */ /* _LOWER_ 7 bits */ unsigned short addr; //设备的地址 char name[I2C_NAME_SIZE]; //设备的名字 struct i2c_adapter *adapter; //设备所属的适配器 struct i2c_driver *driver; //设备的driver /* * 内嵌的标准device模型,其中dev->type标识该设备 * 是个client,其值为i2c_client_type */ struct device dev; /* the device structure */ int irq; //中断号 struct list_head detected; //挂接点,挂接在adapter };
下面是driver的表述结构i2c_driver:
struct i2c_driver { unsigned int class; //支持的类型,与adapter的class相对 /* 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); /* * 内嵌的标准driver,driver的of_match_table成员也用于标识其支持 * 的设备,并且优先级高于id_table */ struct device_driver driver; const struct i2c_device_id *id_table; //支持的client信息表 /* Device detection callback for automatic device creation */ int (*detect)(struct i2c_client *, struct i2c_board_info *); //探测函数 const unsigned short *address_list; //driver支持的client地址 struct list_head clients; //挂接其探测到的支持的设备 };
另外client端有一条全局链表,用于串联所有i2c的client设备,为__i2c_board_list,也就是说client可以静态注册亦可动态
被探测,静态注册挂接在该链表上的结构为:
struct i2c_devinfo { struct list_head list; //连接指针指向前后设备 int busnum; //所在bus的编号 struct i2c_board_info board_info; //板级平台信息相关的结构体 }; //其中 i2c_board_info结构的源码为: 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; //节点 #endi int irq; //中断号 };
i2c_devinfo结构静态注册的信息最后都会被整合集成到client中,形成一个标准的i2c_client设备并注册。
二、i2c核心初始化代码分析
首先看一下i2c平台无关的核心初始化,代码位于drivers/i2c/i2c-core.c下:
static int __init i2c_init(void) { int retval; /* * 注册i2c_bus */ retval = bus_register(&i2c_bus_type); if (retval) return retval; #ifdef CONFIG_I2C_COMPAT /* * 在sys/class下创建适配器目录 */ i2c_adapter_compat_class = class_compat_register("i2c-adapter"); if (!i2c_adapter_compat_class) { retval = -ENOMEM; goto bus_err; } #endif /* * 增加一个虚拟的driver */ 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; } //其中的i2c_bus_type原型为: 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, };
三、i2c_add_driver分析
驱动端的统一接口为i2c_add_driver:
static inline int i2c_add_driver(struct i2c_driver *driver) { /* *注册i2c driver,可能是adapter的,也可能是client的 */ return i2c_register_driver(THIS_MODULE, 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 */ /* * i2c_driver内嵌的标准driver赋值,其bus指定为i2c_bus_type */ 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. */ /*注册标准的driver,driver注册后会去i2c_bus_type的设备链表上匹配 *设备,匹配函数用的是bus端的,也就是i2c_device_match,如果匹配成功 *将建立标准关联,并且将调用bus端的probe函数初始化这个设备,即 *函数i2c_device_probe,下面会逐个分析 */ res = driver_register(&driver->driver); if (res) return res; pr_debug("i2c-core: driver [%s] registered/n", driver->driver.name); /* * 把该driver的clients初始化,该成员连接着这个driver可以操作的具 * 体设备 */ INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ mutex_lock(&core_lock); /* * 遍历挂接在该i2c设备链表上的设备,并对其都调用__process_new_driver * 函数 */ bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver); mutex_unlock(&core_lock); return 0; } /**************************** * 匹配函数i2c_device_match * ****************************/ static int i2c_device_match(struct device *dev, struct device_driver *drv) { /* * i2c_verify_client检查匹配的这个设备是否为i2c_client_type * 类型,如果不是则返回NULL,此处的匹配只是针对i2c设备的 * 不是适配器 */ struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; /* * 如果不是i2c设备类型就返回 */ if (!client) return 0; /* Attempt an OF style match */ /* * 如果定义了CONFIG_OF_DEVICE,那么就利用 * drv.of_match_table成员表进行匹配 */ if (of_driver_match_device(dev, drv)) return 1; /* * 由内嵌的driver得到外面封装的i2c_driver */ driver = to_i2c_driver(drv); /* match on an id table if there is one */ /* * 如果i2c_driver->id_table存在,也就是支持的设备信息表 * 存在,那么利用这个表进行匹配 */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; return 0; } /********************************** * 初始化设备函数i2c_device_probe * **********************************/ static int i2c_device_probe(struct device *dev) { /* * 检查如果设备类型不是client则返回 */ struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; int status; if (!client) return 0; /* * dev->driver指向匹配完成的driver,根据该标准 * driver得到其外围封装的i2c_driver */ driver = to_i2c_driver(dev->driver); /* * 如果该i2c_driver的probe成员或者id_table成员为 * NULL则退出 */ if (!driver->probe || !driver->id_table) return -ENODEV; /* * client的driver成员赋值为该i2c_driver */ client->driver = driver; /* * 唤醒该设备 */ if (!device_can_wakeup(&client->dev)) device_init_wakeup(&client->dev, client->flags & I2C_CLIENT_WAKE); dev_dbg(dev, "probe/n"); /* * 利用i2c_driver的probe成员初始化该设备,此部分为实际平台相关 */ status = driver->probe(client, i2c_match_id(driver->id_table, client)); /* * 失败则清除client指定的driver */ if (status) { client->driver = NULL; i2c_set_clientdata(client, NULL); } return status; } /************************************************************* * 下面看一下当找到一个dev后调用的__process_new_driver函数 * *************************************************************/ static int __process_new_driver(struct device *dev, void *data) { /* * 设备的类型如果不是i2c_adapter类型就推出 * 下面的代码是针对i2c适配器的代码 */ if (dev->type != &i2c_adapter_type) return 0; /* * 如果这个设备代表i2c适配器,则调用i2c_do_add_adapter * 此时的data类型为i2c_driver */ return i2c_do_add_adapter(data, to_i2c_adapter(dev));//根据设备得到他的适配器 //i2c_driver。第一个是i2c_driver } /************************* * i2c_do_add_adapter函数 * *************************/ static int i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap) { /* Detect supported devices on that bus, and instantiate them */ /* * 利用该适配器和该i2c_driver探测该适配器所在的这条i2c总线 * 找到该driver支持的设备并实例化它 */ i2c_detect(adap, driver); /* Let legacy drivers scan this bus for matching devices */ /* * 老版本的探测利用i2c_driver的attach_adapter函数 */ if (driver->attach_adapter) { /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); } return 0; } /**************************** * 重点看一下i2c_detect函数 * ****************************/ 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); /* * 得到该i2c_driver指定的client地址范围 */ address_list = driver->address_list; /* * driver平台相关的detect函数和client地址范围不能为NULL */ if (!driver->detect || !address_list) return 0; /* Set up a temporary client to help detect callback */ /* * 申请一块client内存 */ temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (!temp_client) return -ENOMEM; /* * 申请的client结构的adapter成员设置为当前的adapter */ temp_client->adapter = adapter; /* Stop here if the classes do not match */ /* * 当前adapter的类型如果和driver的类型不一样,则退出 * 例如:适配器的类型可以为传感器,eeprom,driver类型必须 * 与其匹配 */ if (!(adapter->class & driver->class)) goto exit_free; /* * 根据指定的支持的地址范围开始逐一探测 */ for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { dev_dbg(&adapter->dev, "found normal entry for adapter %d, " "addr 0x%02x/n", adap_id, address_list[i]); /* * 临时申请的client的地址设置为这次要探测的地址 */ 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; } /********************************** * 继续跟进i2c_detect_address函数 * **********************************/ 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 */ /* * 检查该地址是否有效,小于0x08或者大于0x77都是无效 * 地址,该函数在后面介绍 */ 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 */ /* * 走到这里将调用平台相关的自定义探测函数去探测该地址 * 上是否设备,并填充i2c_board_info结构体 */ memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = addr; err = driver->detect(temp_client, &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 */ /* * 填充的info名字为空,则结束否则实例化这个设备 */ 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); /* * 根据当前适配器和填充的info实例化该地址上探测到的设备 */ client = i2c_new_device(adapter, &info); /* * 实例化成功将该client挂到该driver的clients链表上 */ if (client) list_add_tail(&client->detected, &driver->clients); //驱动挂到driver下 else dev_err(&adapter->dev, "Failed creating %s at 0x%02x/n", info.type, info.addr); } return 0; } /****************************** * i2c_check_addr_validity函数 * ******************************/ 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_default_probe函数 * *********************************/ static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr) { int err; union i2c_smbus_data dummy; #ifdef CONFIG_X86 /* * 这里是对intel特殊设备的检查,就不深入看下去了 */ 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_WRITE, 0, I2C_SMBUS_QUICK, NULL); /* * i2c_check_functionality函数确定该i2c适配器所支持的通信方式 * 如果支持该方式则调用i2c_smbus_xfer函数 */ else if (i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy); else { dev_warn(&adap->dev, "No suitable probing method supported/n"); err = -EOPNOTSUPP; } return err >= 0; } /****************************** * i2c_check_functionality函数 * ******************************/ static inline int i2c_check_functionality(struct i2c_adapter *adap, u32 func) { return (func & i2c_get_functionality(adap)) == func; } static inline u32 i2c_get_functionality(struct i2c_adapter *adap) { /* * 最终会调用adapter通信函数里面的functionality函数确定支持的 * 通信方式 */ return adap->algo->functionality(adap); } /********************* * i2c_smbus_xfer函数 * *********************/ 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; /* * 如果适配器通信函数中的smbus_xfer函数存在,则直接利用它进行发送 */ if (adapter->algo->smbus_xfer) { i2c_lock_adapter(adapter); /* 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; } i2c_unlock_adapter(adapter); } else /* * 否则利用i2c_smbus_xfer_emulated处理,此处也就是不支持smbus, * 则得利用i2c模拟smbus命令 */ res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, command, protocol, data); return res; } /****************************** * i2c_smbus_xfer_emulated函数 * ******************************/ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { /* So we need to generate a series of msgs. In the case of writing, we need to use only one message; when reading, we need two. We initialize most things with sane defaults, to keep the code below somewhat simpler. */ /* * 为了进行通信我们必须创建msgs结构,当写时,我们需要一个这样的结构就 * 够了,当读的时候,我们需要两个 */ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2]; /* * 读的时候需要两次 */ int num = read_write == I2C_SMBUS_READ ? 2 : 1; /* * 填充需要的两个msg结构 */ struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, { addr, flags | I2C_M_RD, 0, msgbuf1 } }; int i; u8 partial_pec = 0; int status; /* * 将要发送的命令填充到msg0 */ msgbuf0[0] = command; switch (size) { /* * 快速传输,多用于确定该地址有应答 */ case I2C_SMBUS_QUICK: msg[0].len = 0; /* Special case: The read/write field is used as data */ msg[0].flags = flags | (read_write == I2C_SMBUS_READ ? I2C_M_RD : 0); num = 1; break; /* * 字节传输,一次读写一个字节 */ case I2C_SMBUS_BYTE: if (read_write == I2C_SMBUS_READ) { /* Special case: only a read! */ msg[0].flags = I2C_M_RD | flags; num = 1; } break; /* * 命令+单字节形式传输 */ case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 1; else { msg[0].len = 2; msgbuf0[1] = data->byte; } break; /* * 命令+字形式传输 */ case I2C_SMBUS_WORD_DATA: if (read_write == I2C_SMBUS_READ) msg[1].len = 2; else { msg[0].len = 3; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = data->word >> 8; } break; /* * 命令+字形式,需要应答 */ case I2C_SMBUS_PROC_CALL: num = 2; /* Special case */ read_write = I2C_SMBUS_READ; msg[0].len = 3; msg[1].len = 2; msgbuf0[1] = data->word & 0xff; msgbuf0[2] = data->word >> 8; break; /* * 多字节数据模式,字节数传输中不确定 */ case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { dev_err(&adapter->dev, "Invalid block write size %d/n", data->block[0]); return -EINVAL; } for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; } break; /* * 多字节数据传输,需要应答 */ case I2C_SMBUS_BLOCK_PROC_CALL: num = 2; /* Another special case */ read_write = I2C_SMBUS_READ; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { dev_err(&adapter->dev, "Invalid block write size %d/n", data->block[0]); return -EINVAL; } msg[0].len = data->block[0] + 2; for (i = 1; i < msg[0].len; i++) msgbuf0[i] = data->block[i-1]; msg[1].flags |= I2C_M_RECV_LEN; msg[1].len = 1; /* block length will be added by the underlying bus driver */ break; /* * 多字节数据传输,传输字节数确定 */ case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = data->block[0]; } else { msg[0].len = data->block[0] + 1; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) { dev_err(&adapter->dev, "Invalid block write size %d/n", data->block[0]); return -EINVAL; } for (i = 1; i <= data->block[0]; i++) msgbuf0[i] = data->block[i]; } break; default: dev_err(&adapter->dev, "Unsupported transaction %d/n", size); return -EOPNOTSUPP; } i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA); if (i) { /* Compute PEC if first message is a write */ if (!(msg[0].flags & I2C_M_RD)) { if (num == 1) /* Write only */ i2c_smbus_add_pec(&msg[0]); else /* Write followed by read */ partial_pec = i2c_smbus_msg_pec(0, &msg[0]); } /* Ask for PEC if last message is a read */ if (msg[num-1].flags & I2C_M_RD) msg[num-1].len++; } /* * 调用i2c_transfer传输 */ status = i2c_transfer(adapter, msg, num); if (status < 0) return status; /* Check PEC if last message is a read */ if (i && (msg[num-1].flags & I2C_M_RD)) { status = i2c_smbus_check_pec(partial_pec, &msg[num-1]); if (status < 0) return status; } /* * 将得到的数据回传给data */ if (read_write == I2C_SMBUS_READ) switch (size) { case I2C_SMBUS_BYTE: data->byte = msgbuf0[0]; break; case I2C_SMBUS_BYTE_DATA: data->byte = msgbuf1[0]; break; case I2C_SMBUS_WORD_DATA: case I2C_SMBUS_PROC_CALL: data->word = msgbuf1[0] | (msgbuf1[1] << 8); break; case I2C_SMBUS_I2C_BLOCK_DATA: for (i = 0; i < data->block[0]; i++) data->block[i+1] = msgbuf1[i]; break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_BLOCK_PROC_CALL: for (i = 0; i < msgbuf1[0] + 1; i++) data->block[i] = msgbuf1[i]; break; } return 0; } /******************* * i2c_transfer函数 * *******************/ 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). */ /* * 如果适配器的adap->algo->master_xfer函数存在,则调用它把 * 该信息发送出去 */ 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); } /* 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; } i2c_unlock_adapter(adap); return ret; } else { dev_dbg(&adap->dev, "I2C level transfers not supported/n"); return -EOPNOTSUPP; } } /********************************************** * 回过头来看一下i2c_new_device这个实例化函数* **********************************************/ 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; /* * 指定适配器以及platform_data */ client->adapter = adap; client->dev.platform_data = info->platform_data; /* * info->archdata存在将其赋值给client */ 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; /* * 内嵌标准device的赋值 */ 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 dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr); /* * 注册内嵌的标准device */ 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; }
以上就是i2c通用driver添加的流程,下面看一下设备端,适配器的流程
四、i2c_add_adapter分析
int i2c_add_adapter(struct i2c_adapter *adapter) { int id, res = 0; retry: /* * 得到bus号并将其插入搜索树,便于高效查找 * 此处不做深入分析 */ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; mutex_lock(&core_lock); /* "above" here means "above or equal to", sigh */ res = idr_get_new_above(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, &id); mutex_unlock(&core_lock); if (res < 0) { if (res == -EAGAIN) goto retry; return res; } /* * 适配器号赋值,代表i2c的编号 */ adapter->nr = id; return i2c_register_adapter(adapter); } /*********************************************** * 来看一下适配器的注册函数i2c_register_adapter* ***********************************************/ static int i2c_register_adapter(struct i2c_adapter *adap) { int res = 0; /* Can't register until after driver model init */ /* * bus私有属性结构不能为NULL */ if (unlikely(WARN_ON(!i2c_bus_type.p))) { res = -EAGAIN; goto out_list; } rt_mutex_init(&adap->bus_lock); mutex_init(&adap->userspace_clients_lock); INIT_LIST_HEAD(&adap->userspace_clients); /* Set default timeout to 1 second if not already set */ /* * 超时时间设置为1s */ if (adap->timeout == 0) adap->timeout = HZ; /* * 设置内嵌device的名字,指定bus,指定自身类型为适配器 */ dev_set_name(&adap->dev, "i2c-%d", adap->nr); adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; /* * 注册内嵌的标准device,此时将会出现在i2c_bus目录下 */ res = device_register(&adap->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 */ /* * client可以静态的添加,如果发现适配器号也就是i2c号 * 小于动态bus号,说明设备静态添加,则进行扫描 */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); /* Notify drivers */ mutex_lock(&core_lock); /* * 遍历bus的驱动端,对于每一个driver都调用__process_new_adapter */ 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; } /******************************************* * 先来看一下i2c_scan_static_board_info函数* *******************************************/ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; down_read(&__i2c_board_lock); /* * 遍历全局的i2c的client链表,找到该适配器器所代表 * 总线上挂接的设备,用i2c_new_device实例化它, * i2c_new_device在前面已经分析过了,不在赘述 */ list_for_each_entry(devinfo, &__i2c_board_list, list) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) dev_err(&adapter->dev, "Can't create device at 0x%02x/n", devinfo->board_info.addr); } up_read(&__i2c_board_lock); } /************************************** * 再来看一下__process_new_adapter函数* **************************************/ static int __process_new_adapter(struct device_driver *d, void *data) { /* * 同样的归宿到了i2c_do_add_adapter下面,与前面分析的 * __process_new_driver相似,只是driver是针对适配器, * 而这次没有这个限制 */ return i2c_do_add_adapter(to_i2c_driver(d), data); }
依据以上的分析画出流程图如下:
i2c_driver依据内部成员的设定,会走不同的分支,产生不同的作用,下面根据流程前后顺序总结一下:
当发现的是i2c_bus上的一个client时(发生在标准driver注册的匹配):
1、首先会进入到bus定义的匹配函数i2c_device_match如果定义了CONFIG_OF_DEVICE宏并且内部的标准
driver结构定义了of_match_table成员,则利用其进行匹配;
2、否则如果driver->id_table成员设定,则利用其进行匹配,否则匹配失败。
3、如果匹配成功会调用i2c_bus的i2c_device_probe函数,该函数会判断,如果该i2c_driver的probe成员
或者id_table成员为NULL,则返回,否则利用i2c_driver->probe初始化这个client。
当发现的是代表该i2c_bus的上的adapter时(发生在bus的遍历):
1、如果该driver的driver->detect或者address_list为NULL退出
2、如果该adapter->class和driver->class不匹配也退出
3、如果以上都成立最终会调用driver->detect函数,实例化支持的client
4、如果driver->attach_adapter也被设定,含会走旧式的路线,直接利用driver->attach_adapter进行探测
不过,一般不会让3&&4这种结果出现
可见,i2c_driver的设置非常灵活,抓住关键成员就不难掌握其流程。
五、i2c关于dev下节点的产生及其操作
该部分的代码位于rivers/i2c/i2c-dev.c下,我们从头看起:
static int __init i2c_dev_init(void) { int res; printk(KERN_INFO "i2c /dev entries driver/n"); /* * 注册名称为i2c主设备号为89的一个字符设备 */ res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops); if (res) goto out; /* * 在class下产生i2c-dev节点,用于自动产生设备文件 */ i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); if (IS_ERR(i2c_dev_class)) { res = PTR_ERR(i2c_dev_class); goto out_unreg_chrdev; } /* * i2c_add_driver在上面已经分析过了 */ res = i2c_add_driver(&i2cdev_driver); if (res) goto out_unreg_class; return 0; out_unreg_class: class_destroy(i2c_dev_class); out_unreg_chrdev: unregister_chrdev(I2C_MAJOR, "i2c"); out: printk(KERN_ERR "%s: Driver Initialisation failed/n", __FILE__); return res; } //其中i2cdev_driver结构为: static struct i2c_driver i2cdev_driver = { .driver = { .name = "dev_driver", }, .attach_adapter = i2cdev_attach_adapter, .detach_adapter = i2cdev_detach_adapter, };
由于没有关于client的支持表的定义,因此匹配client时就会直接返回, 由于存在成员attach_adapter,因此当匹配adapter时会进入该函数。
/************************************ * 来看一下i2cdev_attach_adapter函数* ************************************/ static int i2cdev_attach_adapter(struct i2c_adapter *adap) { struct i2c_dev *i2c_dev; int res; i2c_dev = get_free_i2c_dev(adap); if (IS_ERR(i2c_dev)) return PTR_ERR(i2c_dev); /* register this i2c device with the driver core */ /* * 以上面注册的i2c_dev_class为父节点在目录class/i2c-dev下 * 产生i2c-0之类的节点,这样上层udev会根据该节点在dev目录下 * 自动创建对应的设备文件 */ i2c_dev->dev = device_create(i2c_dev_class, &adap->dev, MKDEV(I2C_MAJOR, adap->nr), NULL, "i2c-%d", adap->nr); if (IS_ERR(i2c_dev->dev)) { res = PTR_ERR(i2c_dev->dev); goto error; } /* * 产生相关属性文件 */ res = device_create_file(i2c_dev->dev, &dev_attr_name); if (res) goto error_destroy; pr_debug("i2c-dev: adapter [%s] registered as minor %d/n", adap->name, adap->nr); return 0; error_destroy: device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr)); error: return_i2c_dev(i2c_dev); return res; }
通过以上分析可以看到i2c-dev层,找到一个adapter就会自动为其创建设备节点,形式类似于i2c-*,那么当应用层open对应的设备节点的时候,内核会自动调用刚才注册的字符设备的操作函数, 我们先来看一下刚才注册的字符设备的操作集:
static const struct file_operations i2cdev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = i2cdev_read, .write = i2cdev_write, .unlocked_ioctl = i2cdev_ioctl, .open = i2cdev_open, .release = i2cdev_release, };
按照用户层的流程先看一下open函数i2cdev_open:
static int i2cdev_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); //得到次设备号 struct i2c_client *client; struct i2c_adapter *adap; struct i2c_dev *i2c_dev; /* * 次设备号其实是对应i2c总线号,下面函数遍历由次设备构成的链表 * i2c_dev_list,找到上面挂接的号码对应的i2c_dev结构 */ i2c_dev = i2c_dev_get_by_minor(minor); if (!i2c_dev) //没找到,出错 return -ENODEV; adap = i2c_get_adapter(i2c_dev->adap->nr); //得到绑定的adapter if (!adap) return -ENODEV; /* This creates an anonymous i2c_client, which may later be * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE. * * This client is ** NEVER REGISTERED ** with the driver model * or I2C core code!! It just holds private copies of addressing * information and maybe a PEC flag. */ client = kzalloc(sizeof(*client), GFP_KERNEL); //申请个client内存 if (!client) { i2c_put_adapter(adap); return -ENOMEM; } //命名,依据adapter snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); //指定driver,代表创建他的driver client->driver = &i2cdev_driver; //指定适配器 client->adapter = adap; //通过file的私有成员传递创建的这个client file->private_data = client; return 0; }
由open可见,我们要操作i2c下的设备,始终是需要通过adapter,物理上也是如此,操作设备都是通过控制器进行读写的,因此我们打开的始终是adapter而open过程中会创建client,来表述我们主观上是要操作设备。下面在看一下read函数:
static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { char *tmp; int ret; //得到由open传递过来的创建的client struct i2c_client *client = file->private_data; //大小不能超过8192 if (count > 8192) count = 8192; //申请count大小内存 tmp = kmalloc(count, GFP_KERNEL); if (tmp == NULL) return -ENOMEM; pr_debug("i2c-dev: i2c-%d reading %zu bytes./n", iminor(file->f_path.dentry->d_inode), count); //调用i2c_master_recv进行进一步传送 ret = i2c_master_recv(client, tmp, count); if (ret >= 0) //read的信息反馈给用户 ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret; kfree(tmp); return ret; } /**************************** * 其中i2c_master_recv函数为* ****************************/ 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组织信息结构 msg.addr = client->addr; msg.flags = client->flags & I2C_M_TEN; msg.flags |= I2C_M_RD; msg.len = count; msg.buf = buf; //调用i2c_transfer发送 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; }
i2c_transfer函数上面已经分析过了,其会最终调用client所在adapter的adap->algo->master_xfer函数发送。
六、总结
分析了linux下i2c子系统模型及其关键点,针对核心的平台无关代码进行了描述,以上为个人观点,如有不妥,还望指正 ^_^