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; };
关于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; }