Linux i2c驱动框架分析 (一)
Linux i2c驱动框架分析 (二)
Linux i2c驱动框架分析 (三)
通用i2c设备驱动分析
i2c core
i2c核心(drivers/i2c/i2c-core.c)中提供了一组不依赖于硬件平台的接口函数,理解其中的主要函数非常关键,因为 I2C 总线驱动和设备驱动之间赖于i2c核心作为纽带。i2c核心中提供的主要函数如下。
(1)增加/删除i2c_adapter
int i2c_add_adapter(struct i2c_adapter *adapter);
void i2c_del_adapter(struct i2c_adapter *adap);
(2)增加/删除i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
void i2c_del_driver(struct i2c_driver *driver);
#define i2c_add_driver(driver) \
i2c_register_driver(THIS_MODULE, driver)
(3)增加/删除i2c_client
struct i2c_client *i2c_new_device(struct i2c_adapter *adap,
struct i2c_board_info const *info);
struct i2c_client *i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
unsigned short const *addr_list,
int (*probe)(struct i2c_adapter *, unsigned short addr));
void i2c_unregister_device(struct i2c_client *client)
(4)i2c传输、发送和接收
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
int i2c_master_send(const struct i2c_client *client, const char *buf,
int count);
int i2c_master_recv(const struct i2c_client *client, char *buf,
int count);
i2c_transfer()函数用于进行i2c适配器和i2c设备之间的一组消息交互,i2c_master_send()函数和i2c_master_recv()函数内部会调用i2c_transfer()函数分别完成一条写消息和一条读消息。
i2c_transfer()函数本身不具备驱动适配器物理硬件完成消息交互的能力,它只是寻找到i2c_adapter对应的i2c_algorithm,并使用 i2c_algorithm的master_xfer()函数真正驱动硬件流程。
在i2c_core.c中定义了一个总线类型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,
};
这个i2c总线结构体管理着i2c设备与i2c驱动的匹配,删除等操作,i2c总线会调用i2c_device_match函数看i2c设备和i2c驱动是否匹配,如果匹配就调用i2c_device_probe函数,进而调用i2c驱动的probe函数。
i2c设备与驱动
Linux i2c设备驱动的模块加载与卸载
i2c设备驱动的模块加载函数通用的方法是进行通过I2C核心的 i2c_add_driver()函数添加 i2c_driver的工作,而在模块卸载函数中需要做相反的工作:通过i2c核心的i2c_del_driver()函数删除i2c_driver。
Linux i2c设备实例化的多种方法
这里只是介绍其中的几种方法。
-
通过devicetree声明I2C设备
在i2c控制器的节点里声明子节点,每个子节点代表一个i2c设备,如下图所示:
-
显式实例化i2c设备
通过i2c_new_device()或者i2c_new_probed_device()函数,创建并注册i2c_client。 -
从用户空间实例化i2c设备
Example:
//名字为eeprom,地址为0x50的i2c设备注册进内核,挂接在i2c控制器0上
echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device
驱动与设备的匹配
i2c驱动与设备的匹配是在注册驱动或设备时进行匹配的,下面以注册i2c驱动为例,分析匹配过程的细节。
注册i2c驱动:
#define i2c_add_driver(driver) \
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 (WARN_ON(!is_registered))
return -EAGAIN;
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
//设置所属总线为i2c_bus_type
driver->driver.bus = &i2c_bus_type;
INIT_LIST_HEAD(&driver->clients);
//注册驱动
res = driver_register(&driver->driver);
if (res)
return res;
pr_debug("driver [%s] registered\n", driver->driver.name);
/* 探测驱动的address_list列表中的设备地址是否存在,存在则注册设备 */
i2c_for_each_dev(driver, __process_new_driver);
return 0;
}
下面重点分析driver_register函数:
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
//进行一些相关判断
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
//查询是否含有同名驱动
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
/* 把驱动插入到bus的驱动链表,这里涉及设备驱动模型相关知识
* 在/sys/bus/i2c/drivers/目录下创建该驱动的sysfs目录,
* 同时遍历bus的设备链表调用__driver_attach函数
*/
ret = bus_add_driver(drv);
if (ret)
return ret;
//增添属性相关
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
return ret;
}
__driver_attach:
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
int ret;
/* 调用bus里的match函数进行匹配,对于i2c bus对应函数i2c_device_match
* 匹配成功返回1
*/
ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
return 0;
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
} /* ret > 0 means positive match */
......
//判断该设备是否已匹配了驱动
if (!dev->driver)
//会调到bus里的probe函数,对于i2c bus对应函数为i2c_device_probe(如果不存在则调用驱动的probe函数)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
分析i2c_device_match函数,看看具体怎么匹配的:
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;
//设备树匹配
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
//id表匹配
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;
}
有多种匹配方式,这里分析一下id表匹配:
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) //比较name
return id;
id++;
}
return NULL;
}
如果匹配成功,driver_match_device函数返回1,之后会调到bus里的probe函数,对于i2c bus对应函数为i2c_device_probe:
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;
......
//调用驱动的probe函数
status = driver->probe(client, i2c_match_id(driver->id_table, client));
......
}
i2c驱动的探测功能
i2c驱动含有一个设备地址列表address_list:
struct i2c_driver {
unsigned int class;
......
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};
在注册i2c驱动时,通过适配器,探测address_list中对应地址的设备是否存在,如果存在则注册i2c设备。
在注册i2c驱动时,会遍历i2c bus上的适配器,调用__process_new_driver函数:
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
.....
//可以得知i2c适配器也被当做一种设备插入到i2c bus的设备链表上
i2c_for_each_dev(driver, __process_new_driver);
return 0;
}
__process_new_driver:
static int __process_new_driver(struct device *dev, void *data)
{
//判断是否为i2c适配器
if (dev->type != &i2c_adapter_type)
return 0;
return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}
i2c_do_add_adapter:
static int i2c_do_add_adapter(struct i2c_driver *driver,
struct i2c_adapter *adap)
{
/* 探测 */
i2c_detect(adap, driver);
/* 这是老式的探测方法,已不推荐使用 */
if (driver->attach_adapter) {
dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n",
driver->driver.name);
dev_warn(&adap->dev,
"Please use another way to instantiate your i2c_client\n");
/* 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);
address_list = driver->address_list;
//如果驱动未提供detect函数和address_list,直接返回
if (!driver->detect || !address_list)
return 0;
/* Warn that the adapter lost class based instantiation */
if (adapter->class == I2C_CLASS_DEPRECATED) {
dev_dbg(&adapter->dev,
"This adapter dropped support for I2C classes and won't auto-detect %s devices anymore. "
"If you need it, check 'Documentation/i2c/instantiating-devices' for alternatives.\n",
driver->driver.name);
return 0;
}
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
return 0;
/* 创建一个临时的i2c_client,用于帮助探测 */
temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!temp_client)
return -ENOMEM;
temp_client->adapter = adapter;
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]);
temp_client->addr = address_list[i];
//设置好临时的i2c_client后,探测设备地址
err = i2c_detect_address(temp_client, driver);
if (unlikely(err))
break;
}
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;
/* 检查addr是否有效 */
err = i2c_check_7bit_addr_validity_strict(addr);
if (err) {
dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
addr);
return err;
}
/* 检查addr是否与挂在适配器上的设备的地址相同 */
if (i2c_check_addr_busy(adapter, addr))
return 0;
/* 向地址为addr的设备发送信号,可是否有回应 */
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;
/* 程序执行到这里,说明存在地址为addr的设备,调用驱动的detect函数
* 在驱动的detect函数中,要初始化i2c_board_info->type,即i2c设备的name
*/
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;
}
/* 检查name是否初始化 */
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 */
if (adapter->class & I2C_CLASS_DEPRECATED)
dev_warn(&adapter->dev,
"This adapter will soon drop class based instantiation of devices. "
"Please make sure client 0x%02x gets instantiated by other means. "
"Check 'Documentation/i2c/instantiating-devices' for details.\n",
info.addr);
dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
info.type, info.addr);
//增添新的i2c设备
client = i2c_new_device(adapter, &info);
if (client)
//把i2c设备插入驱动的clients链表
list_add_tail(&client->detected, &driver->clients);
else
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
info.type, info.addr);
}
return 0;
}