在内核中已经提供I2C子系统,在linux系统中,I2C驱动结构如下图所示:
其中从上图可以I2C由三大部分组成:
1、I2C核心:I2C核心提供了总线驱动和设备驱动的注册、注销的方法,I2C通信方法,与具体适配器无关的代码以及检测设备地址的代码等。
2、I2C总线驱动:对I2C硬件体系结构中适配器的实现,控制I2C总线驱动的代码,控制I2C适配器以主控方式产生开始位,停止位,读写以及设备读写方式,产生ack等。
3、I2C客户驱动程序:是对I2C硬件体系结构设备端得实现。
我们在分析其子系统之前,还是来看看其数据结构
i2c_adapter结构体表示一个物理的i2c总线控制器
点击(此处)折叠或打开
struct i2c_adapter {
struct module *owner;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
/* data fields that are valid for all devices */
struct rt_mutex bus_lock;
int timeout; /* in jiffies */
int retries;
struct device dev; /* the adapter device */
int nr;
char name[48]; //适配器名字
struct completion dev_released; //用于同步
struct mutex userspace_clients_lock;
struct list_head userspace_clients;
};上面包含i2c_algorithm,其对应一套通信方法
点击(此处)折叠或打开
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);//I2C传输函数指针
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data *data);//SMBUS传输函数指针
u32 (*functionality) (struct i2c_adapter *);//返回适配器支持的功能
};
一个i2c适配器需要i2c_algorithm中提供的通信函数来控制适配器产生特定的访问函数。其中提供了关键的函数master_xfer()用于产生i2c访问周期需要的信号,以i2c_msg为单位
点击(此处)折叠或打开
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};i2c_driver代表i2c从设备驱动
点击(此处)折叠或打开
struct i2c_driver {
unsigned int class;
int (*attach_adapter)(struct i2c_adapter *) __deprecated;//适配器函数指针
int (*detach_adapter)(struct i2c_adapter *) __deprecated;
/* 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 *);
void (*alert)(struct i2c_client *, unsigned int data);
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;
struct list_head clients;
};i2c_client代表i2c从设备
点击(此处)折叠或打开
struct i2c_client {
unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
struct device dev; /* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
};
i2c_driver与i2c_client是一对多的关系,一个i2c_driver上可以支持多个同等类型的i2c_client。i2c_adapter与i2c_client的关系与i2c硬件体系中适配器和从设备的关系一致,i2c_client依附在i2c_adapter。
下面来看看内核提供任何去注册一个i2c的设备驱动
1.直接使用i2c_register_board_unfo完成设备注册,这种方法适合于i2c总线上预先已知设备,因此可以预先声明i2c设备在哪条总线上,在通过数组结构i2c_board_info,内核实例为arch\arm\mach-omap2\board-h4.c。
点击(此处)折叠或打开
static struct i2c_board_info __initdata h4_i2c_board_info[] = {
{
I2C_BOARD_INFO("isp1301_omap", 0x2d),
.irq = OMAP_GPIO_IRQ(125),
},
{ /* EEPROM on mainboard */
I2C_BOARD_INFO("24c01", 0x52),
.platform_data = &m24c01,
},
{ /* EEPROM on cpu card */
I2C_BOARD_INFO("24c01", 0x57),
.platform_data = &m24c01,
},
};
点击(此处)折叠或打开
static void __init omap_h4_init(void)
{
(...)
i2c_register_board_info(1, h4_i2c_board_info,
ARRAY_SIZE(h4_i2c_board_info));
(...)
}那么内核怎么完成匹配呢?首先来看看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;
}这上面只做了一个非常重要的,将i2c_board_info放入到__i2c_board_list链表,而这个info中存放的是i2c通信非常重要的,设备名字和设备地址。那么链表何时使用呢?这个在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);
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);
}该函数遍历挂载__i2c_board_list链表上面的i2c设备的信息,也就是我们在启动的时候指出的i2c设备的信息,如果指定设备位于adapter所在的i2c总线上,那么就调用i2c_new_device()。
2.直接使用2c_new_device, i2c_new_probed_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;
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;
/* 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;
}该函数只是device_register,但是上面出现了一个新的结构,i2c_client,其实它就是一个struct device的i2c设备的封装。在client里保存该设备的相关信息,client->adapter指向了它所在的adapter。clent->dev所在的bus为i2c_bus_type,在device_register注册的时候,会调用总线的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;
/* Attempt an OF style match */
if (of_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;
}
点击(此处)折叠或打开
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;
}上面是匹配driver的id_table的名字和client的名字是否相同,那么会调用驱动的probe函数。
下面在分析下i2c_new_probed_device有啥不一样,前面一个认为设备肯定存在,而后面的是对于已经识别出来的设备,才会创建。
点击(此处)折叠或打开
for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
/* Check address validity */
if (i2c_check_addr_validity(addr_list[i]) < 0) {
dev_warn(&adap->dev, "Invalid 7-bit address "
"0x%02x\n", addr_list[i]);
continue;
}
/* Check address availability */
if (i2c_check_addr_busy(adap, addr_list[i])) {
dev_dbg(&adap->dev, "Address 0x%02x already in "
"use, not probing\n", addr_list[i]);
continue;
}
/* Test address responsiveness */
if (probe(adap, addr_list[i]))
break;
}3.直接i2c_add_driver
前面的2中方法,都要实现确定适配器,如果我们不知道这个i2c设备在那个适配器上,怎么办?内核提供了一种去class表示在所有的适配器上查找一些i2c设备的地址。
点击(此处)折叠或打开
static struct i2c_driver at24_driver = {
.driver = {
.name = "at24",
.owner = THIS_MODULE,
},
.probe = at24_probe,
.remove = __devexit_p(at24_remove),
.id_table = at24_ids,
};
点击(此处)折叠或打开
static int __init at24_init(void)
{
if (!io_limit) {
pr_err("at24: io_limit must not be 0!\n");
return -EINVAL;
}
io_limit = rounddown_pow_of_two(io_limit);
return i2c_add_driver(&at24_driver);
}而i2c_add_diver只是调用i2c_register_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);
if (res)
return res;
/* Drivers should switch to dev_pm_ops instead. */
if (driver->suspend)
pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
driver->driver.name);
if (driver->resume)
pr_warn("i2c-core: driver [%s] using legacy resume method\n",
driver->driver.name);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
i2c_for_each_dev(driver, __process_new_driver);
return 0;
}上面比较主要的是driver_register,同事遍历driver->client链表,会调用driver->detect的函数。