I2C总线驱动是对适配器端的实现,其含有适配器数据结构struct i2c_adapter,适配器算法数据结构struct i2c_algorithm。I2C设备驱动是对设备端的实现和控制,其含有设备驱动结构i2c_driver和设备客户端结构struct i2c_client。
以下为i2c_driver结构体,里面提供了通用的操作i2c设备的接口函数.
struct i2c_driver {
unsigned int 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);
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;
};
client端有一条全局链表,用于串联所有i2c的client设备,为__i2c_board_list,如何将client链接到__i2c_board_list上去呢?内核提供了另一个数据结构,静态注册挂接在该链表上的结构为:
struct i2c_devinfo {
struct list_head list; /*连接指针指向前后设备*/
int busnum; /*所在bus的编号*/
struct i2c_board_info 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;
#endif
int irq;
};
i2c_devinfo结构静态注册的信息最后都会被整合集成到client中,形成一个标准的i2c_client设备并注册。
关于SMBus协议的说明:Intel制定了SMBus标准用于低速通讯。SMBus二线接口与I2C接口非常相似。SMBus也使用一条数据线(SMBDATA)和一条时钟线(SMBCLK)实现通讯。I2C接口和SMBus接口的主要区别是最大和最小时钟速度。SMBCLK必须在10kHz和100kHz之间。SMBCLK和SMBDATA线也需要上拉电阻。3V供电时上拉电阻大于8.5k ,5V供电时上拉电阻大于14k 。SMBus工作电压范围在3V和5V之间,大于2.1V为高电平,低于0.8V为低电平。struct i2c_adapter对应于物理上的一个适配器,而struct i2c_algorithm对应于一套通讯方法。i2c_algorithm提供一些控制适配器发送或接收函数,对于i2c总线需要初始化master_xfer函数,对于smbus总线需要初始化smbus_xfer函数。master_xfer函数是以i2c_msg为单位进行控制的,其结构如下:
struct i2c_msg {
__u16 addr; //从设备地址
__u16 flags; //动作标志:读或写
#define I2C_M_TEN 0x10 //器件地址是10Bit
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000 //意味当前i2c_msg不发送start信号
#define I2C_M_REV_DIR_ADDR 0x2000 //把读写标志位反转
#define I2C_M_IGNORE_NAK 0x1000//当前i2c_msg忽略I2C器件的ack和nack信号。
#define I2C_M_NO_RD_ACK 0x0800 //表示在正行读操作时不去ACK
__u16 len; //信息长度
__u8 *buf; //信息缓冲区首地址
};
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设备也需要驱动。在驱动端提供统一的添加驱动接口为:i2c_add_driver
static inline int i2c_add_driver(struct i2c_driver *driver)
{
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 */
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;
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
/* Walk the adapters that are already present */
mutex_lock(&core_lock);
bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
mutex_unlock(&core_lock);
return 0;
}
driver_register函数注册后会去i2c_bus_type的设备链表上匹配设备,调用driver中的i2c_device_match,如果匹配成功将建立标准关联,并且将调用bus端的probe函数初始化这个设备,即函数i2c_device_probe.
bus_for_each_dev函数循环遍历挂接在i2c bus总线上的设备,并对每个设备调用__process_new_driver函数。
根据dev得到 i2c_client,根据drv得到i2c_driver,然后根据driver->id_table->name 与 client->name比较。匹配成功说明由设备找到了对应的驱动程序
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = i2c_verify_client(dev);/* 检查是否为client类型,而不是adapter类型 */
struct i2c_driver *driver;
if (!client)
return 0;
driver = to_i2c_driver(drv); /*根据device_driver获得i2c_driver结构体指针*/
/* 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;
}
接着调用初始化设备函数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;
/*dev->driver指向匹配完成的driver*/
driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table)
return -ENODEV;
client->driver = driver;
/*唤醒该设备*/
if (!device_can_wakeup(&client->dev))
device_init_wakeup(&client->dev,
client->flags & I2C_CLIENT_WAKE);
dev_dbg(dev, "probe\n");
/*跳到驱动里,执行驱动程序里的probe函数*/
status = driver->probe(client, i2c_match_id(driver->id_table, client));
if (status) {/*失败将清除client指定的driver内容*/
client->driver = NULL;
i2c_set_clientdata(client, NULL);
return status;
}
/*电源管理中设置该设备有效*/
pm_runtime_set_active(dev);
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));//to_i2c_adapte根据设备得到他的适配器,第一个参数是i2c_driver
}
static int i2c_do_add_adapter(struct i2c_driver *driver,
struct i2c_adapter *adap)
{
/* Detect supported devices on that bus, and instantiate them */
i2c_detect(adap, driver);
/* Let legacy drivers scan this bus for matching devices */
if (driver->attach_adapter) {
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
}
return 0;
}
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;
if (!driver->detect || !address_list)
return 0;
/* Set up a temporary client to help detect callback */
temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (!temp_client)
return -ENOMEM;
temp_client->adapter = adapter;
/* Stop here if the classes do not match 适配器的类型可以为传感器,eeprom,driver类型必须与其匹配*/
if (!(adapter->class & driver->class))
goto exit_free;
/* Stop here if the bus doesn't support probing */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
if (address_list[0] == I2C_CLIENT_END)
goto exit_free;
dev_warn(&adapter->dev, "Probing not supported\n");
err = -EOPNOTSUPP;
goto exit_free;
}
/*根据地址列表匹配执行i2c_detect_address*/
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];
err = i2c_detect_address(temp_client, driver);
if (err)
goto exit_free;
}
exit_free:
kfree(temp_client);
return err;
}
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 */
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 调用驱动里的detect函数*/
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 */
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);
client = i2c_new_device(adapter, &info);/**实例探测到的设备**/
if (client)
list_add_tail(&client->detected, &driver->clients);/*将当前新生成的client添加到driver->client链表的末尾*/
else
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
info.type, info.addr);
}
return 0;
}