一、i2c driver的组成部分
I2C驱动由I2C核心、I2C主控制器驱动程序与I2C从设备驱动程序三部分组成。
1、i2c主控制器(adapter):
属于总线驱动程序。对于嵌入式处理器,内部都集成了一个I2C主控制器,其通过I2C与外设进行通信,在通信过程中,作为主设备。I2C主控制器驱动程序一般由CPU厂商完成。
2、i2c 核心:由主控制器驱动程序与从设备驱动程度可利用的函数与数据结构组成,其使得从设备驱动独立于主控制器驱动程序。I2C核心的代码由操作系统已经完成,其主要依据为I2C的通信协议。
3、i2c slave :挂载在CPU的I2C总线的外围设备(如触摸屏,感应器等设备)的驱动程序。在I2C通信过程中,外围设备作为从设备。
除了以上三部分程序外,Linux还支持i2c-dev。它允许在用户模式下实现i2c从设备驱动程序。
二、i2c core
一般Linux驱动的核心层有两部分的工作:一是为某一类设备或者总线设备注册一个class或者bus以统一管理这类设备;另一个是给设备驱动程序或者上层提供一些统一的接口,让驱动程序通过这些接口向核心层注册一个驱动设备。
i2c core第一步就是创建一个bus的设备模型:代码路径:
driver/i2c/i2c-core.c
static int __init i2c_init(void)
{
int retval;
retval = bus_register(&i2c_bus_type);
if (retval)
return retval;
#ifdef CONFIG_I2C_COMPAT
i2c_adapter_compat_class = class_compat_register("i2c-adapter");
if (!i2c_adapter_compat_class) {
retval = -ENOMEM;
goto bus_err;
}
#endif
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;
}
bus_type结构的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,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
i2c_bus_type匹配的规则是i2c slave与slave driver。match函数其匹配的依据i2c slave name与i2c slave driver name。当匹配成功后,会调用i2c_device_probe函数,该probe函数再会调用slave driver中的probe函数。
core 层的流程图如下:
三、i2c adapter
i2c adapter 的核心结构为struct i2c_adapter。其表示一个i2c control,也可以理解为一条i2c bus。
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;
};
#defineI2C_CLASS_HWMON (1<<0)/* lm_sensors,... */
#defineI2C_CLASS_DDC (1<<3)/* DDC bus ongraphics adapters */
#defineI2C_CLASS_SPD (1<<7)/* Memory modules*/
I2C_CLASS_HWMON:一般i2c主控制器都支持该类型。lm_sensors是linux的一个监控硬件的项目,具体可查看www.lm-sensors.org。
I2C_CLASS_DDC:显示器数据通道。DDC(DisplayDataChannel)是一个I2C通道,是PC主机用于访问显示器存储器以获取显示器中EEPROM中的EDID格式数据,确定显示器的显示属性(如分辨率、纵横比等)信息的数据通道。如15针的VGA接口,其12pin与15pin可用作i2c的SDA与SDL线。
I2C_CLASS_SPD:SPD(SerialPresenceDetect)是1个8针的SOIC封装(3mm*4mm)256字节的EEPROM(ElectricallyErasableProgrammableROM电可擦写可编程只读存储器)芯片。
通常该成员变量都初始化为I2C_CLASS_HWMON。
const struct i2c_algorithm *algo:在i2c总线上完成主从设备之间数据通信的算法,i2c的数据传输就是通过该结构去完成的
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags,
char read_write,u8 command, int size, union i2c_smbus_data *data);
u32 (*functionality) (struct i2c_adapter *);
};
master_xfer:i2c具体的传输方法,如果不支持直接赋空就行,参数struct i2c_msg表示的是一次传输,一次传输可以包含多个字节,其中包括传输的数据。
include/linux/i2c.h
struct i2c_msg {
__u16 addr; /* slave address */
__u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /*length will be first received byte*/
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
addr:从设备的地址,可取7位或10位,如果是10位的话,flag必须设置为I2C_M_TEN,adapter也必须支持I2C_FUNC_10BIT_ADDR
flags:信息传输标志位,可取值如下:
I2C_M_TEN:表示地址为10位。
I2C_M_RD:表示是读操作,即从从设备中读取数据到主控制器中。
I2C_M_NOSTART:设置这个标志意味当前i2c_msg不发送start信号。如果一个i2c_msg没有定义I2C_M_NOSTART而且又不是msgs序列里的第一个i2c_msg,则回发送Rs信号。用于Rs的传输方法。
1.msgs序列第一个数据必须是地址,所以必须不定义这个标志位;
2.在进行读数据,当传送数据方法发生改变时,如从写操作转变为读操作时,会发重复start信号,所以不定义这个标志位;
3.其它情况下一的i2c_msg,则应该定义这个标志。
I2C_M_REV_DIR_ADDR:表示把读写标志位反转,也就是读是把相应位置0。
I2C_M_IGNORE_NAK:正常情况下,当接收到NAK信号时,表示停止发送数据。如果设置这个标志,意味把NAK当作ACK信号,则会继续发送数据。
I2C_M_NO_RD_ACK:这个标识表示在进行读操作时,主设备忽略ACK与NAK信号。
I2C_M_RECV_LEN:将接收数据的长度放在第一字节中。
注意,上面说的读写都是相对主控制器,也就是CPU的I2C控制器而言的。
len:Number of data bytes in @buf being read from or written to the I2C slave address.
buf:The buffer into which data is read, or from which it's written.
master_xfer中的另一个参数num表示的是要传输的消息个数。
master_xfer实现方法:一般I2C主控制器,只有一个字节大小的寄存器来循环传输数据,通常做法是将一次传递的消息保存到内存变量中,然后初始化I2C主控制器,发送开始第一个字节数据(包括从设备地址与数据传输方向)到数据寄存器中,接着等待I2C主控制器中断的发生(表示一个字节数据传输完成),在中断中,向数据寄存器写入下一个要传输的数据或者从数据寄存器读数据。
smbus_xfer:SMBus的传输的方法,如果为空,其将采用master_xfer的传输方法。
functionality:i2c主控制器支持的功能。支持的功能可取的值有:
#define I2C_FUNC_I2C 0x00000001
#define I2C_FUNC_10BIT_ADDR 0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_NOSTART etc. */
#define I2C_FUNC_SMBUS_PEC 0x00000008
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK 0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
.........
i2c_adapter结构中的algo_data:保存了其算法的私有数据,在struct i2c_algorithm的方法中使用。
timeout:传递超时时间,单位是jiffies,如果没初始化,默认值为HZ,也就是时间为1s。
retries:传输一次消息重试的次数。如果消息传输失败,返回-EAGAIN,则重试retries-1次(总共传输retries次)。
nr:i2c总线的编号,从0开始。
name:i2c从设备的名称。
completiondev_released:释放i2c_adapter的completion
i2c adapter driver是通过注册函数i2c_add_adapter(structi2c_adapter *)向i2c核心注册adapter的,注册与注销函数如下:
int i2c_add_adapter(struct i2c_adapter *);
int i2c_add_numbered_adapter(struct i2c_adapter *);
int i2c_del_adapter(struct i2c_adapter *);
i2c_add_numbered_adapter(structi2c_adapter*)使用静态的Bus编号,也就是由i2c_adapter->nr指定。其实际还是调用了i2c_add_adapter()函数。i2c_add_adapter()使用的动态的Bus编号,动态Bus编号是从静态编号+1开始的,更多的情况下,使用的是i2c_add_numbered_adapter。
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
int id;
int status;
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
if (adap->nr & ~MAX_ID_MASK)
return -EINVAL;
retry:
if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
return -ENOMEM;
mutex_lock(&core_lock);
/* "above" here means "above or equal to", sigh;
* we need the "equal to" result to force the result
*/
status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
if (status == 0 && id != adap->nr) {
status = -EBUSY;
idr_remove(&i2c_adapter_idr, id);
}
mutex_unlock(&core_lock);
if (status == -EAGAIN)
goto retry;
if (status == 0)
status = i2c_register_adapter(adap);
return status;
}
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
代码第9~10行,判断adap->nr是否为-1,如果是,则表示使用动态分配Bus号,则直接调用i2c_add_adapter函数。
代码第14~29行,通过IDR分配adap->nr这个数,并且该IDR与该i2c_adapter相关联。
代码第32行,最后调用i2c_register_adapter()注册该i2c_adapter
i2c_add_adapter与i2c_add_numbered_adapter的开始代码都是完成的对BUS编号的IDR分配。当分配成功后,就执行i2c_register_adapter(adapter)函数。
static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0;
/* Can't register until after driver model init */
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 */
if (adap->timeout == 0)
adap->timeout = HZ;
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
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 */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* Notify drivers */
mutex_lock(&core_lock);
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;
}
代码第6~9行,判断i2c_bus_type是否注册,也就是判断核心层的代码是否已经执行。
代码12~21行,判断i2c_adapter的name与algo成员是否为空。
代码31~34行,注册主设备的device设备模型,这样在/sys/bus/devices/目录下则会有“i2c-%d”的主设备目录。第33行,设置adap->dev.type=&i2c_adapter_type,这样在“i2c-%d”目录下会有三个属性文件name、new_device、delete_device。
代码49~50行,if(adap->nr<__i2c_first_dynamic_bus_num)为真,也就是使用静态注册的i2c_adapter,则会调用i2c_scan_static_board_info函数。需要说明的是,当使用i2c_register_board_info注册从设备时,其参数busnum指定的总线的i2c_adapter必须要静态注册。
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_scan_static_board_info函数会遍历__i2c_board_list链表,找到与主控制器adapter相同bus号的次设备i2c_devinfo结构。然后调用i2c_new_device()创建与初始化i2c_client结构与device设备模型。i2c_board_list与i2c_devinfo会在下面的slave driver中讲解。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;
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;
#ifdef CONFIG_OF
client->dev.of_node = info->of_node;
#endif
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr);
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;
}
EXPORT_SYMBOL_GPL(i2c_new_device);
当i2c_adapter->nr与devinfo->busnum相等,也就是主设备的BUS编号与从设备的BUS号相同。i2c_new_device()则会创建与初始化i2c_client结构,注册从设备device模型。
代码83~101行,创建i2c_client结构并做初始化。
代码104~109行,检查从设备的地址是否有效,从设备的地址在初始化i2c_board_info结构中会初始化。
代码112~114行,检查该总线上是否已经有从设备使用该地址。
代码116~130行,为从设备创建device设备模型。这儿需要说明,从设备的device设备模型的父设备是对应总线的主设备的device设备模型。从设备的dev.type注意要与主设备i2c_adapter的dev.type区分开来。
代码54行,当初始化完成从设备i2c_client结构与从设备device设备模型后,则会遍历所有的从设备驱动,调用函数__process_new_adapte函数。
static int __process_new_adapter(struct device_driver *d, void *data)
{
return i2c_do_add_adapter(to_i2c_driver(d), data);
}
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) {
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_do_add_adapter实现的是从设备的侦测,详见i2c slave 侦测
i2c_register_adapter的函数流程如下:
四、i2c slave
1、注册从设备
在i2c中,从设备用结构体struct i2c_client描述:
include/linux/i2c.h
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;
};
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
/* Must equal I2C_M_TEN below */
#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
I2C_CLIENT_PEC:表明使用SMBusPacket Error Checking的功能。主控制器要支持该功能(I2C_FUNC_SMBUS_PEC)。
I2C_CLIENT_TEN:从设备为十位地址。如果有该标志位,则传递的i2c_msg必须有标志位I2C_M_TEN标志,并且主控制器必须要支持十位地址的从设备,也就是主控制器的functionality必须包含I2C_FUNC_10BIT_ADDR。
I2C_CLIENT_WAKE:表示从设备有将系统从sleep状态唤醒的功能。
addr:表示的是从设备的地址,如果是10位地址的话,那么传输的格式如下:
第一个字节前5位为1110b,接着两位为addr的高2位,第二个字节传递低8位地址。
不过,一般向bus加入从设备并不直接定义i2c_client结构,因为从设备的定义是在板级程序中加入的,其调用使用的是arch_initcall(),而主控制器的驱动使用的module_init(),其优先级低于arch_initcall(),初始化i2c_client需要指定其主控制器i2c_adapter,而i2c_adapter的定义与初始化是主控制器的驱动程序中完成的。所以,在板级程序中定义从设备使用结构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;
struct device_node *of_node;
int irq;
};
type:对应i2c_client的name。设备的名字。
flags与addr对应i2c_client的flags与addr。
platform_data:私有数据。
irq:使用的irq号。
内核定义了一宏来简单定义一个i2c_board_info结构:
#define I2C_BOARD_INFO(dev_type, dev_addr) \
.type = dev_type, .addr = (dev_addr)
一般一组I2C总线有多个从设备,则需要定义多个i2c_board_info结构。如:
static struct i2c_board_info i2c_devs0[] __initdata = {
{ I2C_BOARD_INFO("24c08", 0x50), },
{ I2C_BOARD_INFO("wm8580", 0x1b), },
{ I2C_BOARD_INFO("wm8312", 0x34),
.platform_data = &smdk6410_wm1192_pdata,
.irq = S3C_EINT(12),
},
};
定义完i2c从设备后,接着就向i2c bus注册该设备,使用
int i2c_register_board_info(intbusnum,structi2c_board_infoconst*info,unsignedn);
其中,busnum指定要向哪条i2c bus加入该设备,info指定要加入设备的 i2c_board_info,n表示的是要注册的设备的个数,具体实现如下: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_register_board_info会为每一个i2c_board_info分配一个中间结构i2c_devinfo
struct i2c_devinfo {
struct list_head list;
int busnum;
struct i2c_board_info board_info;
};
代码第45行,__i2c_board_list为一个全局链表头。
从上面源码可以看出,i2c_register_board_info()做的工作就是:为每个设备分配i2c_devinfo结构体,然后将i2c_devinfo加入到全局链表__i2c_board_list中。这样,从__i2c_board_list链表就可以找出所有的I2C总线上的所有从设备。
i2c_register_board_info的流程图如下:
i2c_register_board_info函数主要创建与初始化i2c_devinfo结构,并把该结构加入到了__i2c_board_list链表中。
那么什么时候,从设备会注册到相应的I2C总线上呢?那就是在主控制器的驱动程序中。主控制的驱动程序会调用i2c_register_adapter(structi2c_adapter*adap)函数结构向I2C核心注册主控制器,而i2c_register_adapter()就完成了将从设备加入到相应I2C总线上。详细内容见上面的i2c_adapter。
I2C注册从设备有两个方法,一种是静态的注册,就是使用i2c_regisger_board_info函数;另外一种方法就是侦测方法。侦测方法实现参考下面的i2c slave 侦测
2、i2c slave driver
从设备驱动用struct i2c_driver描述:
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, it will be removed in a
* near future.
*/
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 *);
/* 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;
};
上面各个成员函数中,probe、remove、suspend、resume、shutdown与platform_driver中成员函数的功能一样,只是参数由platform_device变成i2c_client。其中probe函数中第二个参数i2c_device_id对应i2c_driver->id_table,而i2c_driver->id_table需要在从设备的驱动程序中进行初始化
struct i2c_device_id {
char name[I2C_NAME_SIZE];
kernel_ulong_t driver_data /* Data private to the driver */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
结构i2c_device_id有两个功能,一个是从设备与从设备驱动的匹配,当name相同时,就表示匹配成功,所以该结构必须在从设备驱动中初始化。另一个功能是保存私有数据,传递给probe函数。一般i2c_device_id使用如下:
static const struct i2c_device_id lm73_ids[] = {
{ "lm73", 0 },
{ /* LIST END */ }
};
i2c_device_id私有数据的作用是应付多个从设备使用一个从设备驱动。比如现在有多个从设备,其功能上基本一致,只是存在很小差异,这样就可以只使用一个从设备的驱动程序,i2c_device_id可列出所有的从设备,而私有数据则保存这些设备的差异性。
#define I2C_CLASS_HWMON (1<<0) /* lm_sensors, ... */
#define I2C_CLASS_DDC (1<<3) /* DDC bus on graphics adapters */
#define I2C_CLASS_SPD (1<<7) /* Memory modules */
如果要使用int(*detect)(struct i2c_client *,struct i2c_board_info*)成员函数,则必须定义class成员。且要属于i2c_adapter的class。
int(*detect)(struct i2c_client *,struct i2c_board_info *)
检测函数,用于侦测从设备,也就是动态注册次设备。一般该函数读取从设备某些特殊寄存器,如设备ID来确认设备的正确性,如果从设备检测成功,则返回0,并应该将i2c_driver的名称赋值给i2c_board_info->type。
const unsignedshort *address_list;
从设备的可用地址列表,用于动态注册次设备使用。用于设备有可选的地址或者使用同一驱动的多个相似设备有着不同的地址。如:
staticconst unsigned short normal_i2c[] = { 0x48,0x49, 0x4a, 0x4c,
0x4d, 0x4e,I2C_CLIENT_END };
其结束用I2C_CLIENT_END。
在动态注册从设备驱动时,系统会与address_list列表中的所有地址上的从设备进行通信,如果通信成功,则会调用detect()成员函数。所以要想系统成功调用detect()成员函数,也就是使用动态注册从设备方法,则需要:
1.初始化i2c_driver->class,且要与i2c_adapter->class相容。
2.初始化i2c_driver->address_list。
3.初始化i2c_driver->detect()函数。detect()要将i2c_driver的名称赋值给i2c_board_info->type。
实现了detect()成员函数,就可以不用在板级驱动中定义i2c_board_info结构。
完成了i2c_driver成员变量,则调用函数i2c_add_driver()将驱动加入到内核中。
int i2c_register_driver(struct module *, struct i2c_driver *);
void i2c_del_driver(struct i2c_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;
/* 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;
}
EXPORT_SYMBOL(i2c_register_driver);
i2c_register_driver()主要做了两件事。一是调用driver_register()注册device_driver设备模型。二是扫描挂载到I2Cbus上的所有设备,执行__process_new_driver函数。
static int __process_new_driver(struct device *dev, void *data)
{
if (dev->type != &i2c_adapter_type)
return 0;
return i2c_do_add_adapter(data, to_i2c_adapter(dev));
}
挂载到I2C总线上的设备有两种,一种是i2c_adapter设备,一种是采用i2c_board_info静态注册的从设备。
代码46行,会判断设备是否为i2c_adapter设备,如果是则将执行i2c_do_add_adapter(data,to_i2c_adapter(dev)),这就是动态侦测的函数。这儿判断的是i2c_adapter设备,因为我们是在i2c_driver驱动中侦测所有i2c_adapter上的符合该驱动的从设备i2c_client。
i2c_driver 的流程图如下:
3、i2c slave 侦测
在注册i2c_adapter时,会遍历挂载在I2CBus上的所有i2c_driver,对所有的i2c_driver执行i2c_do_add_adapter函数;在注册i2c_driver时,会遍历挂载在I2CBus上的所有i2c_adapter设备,同样也会执行i2c_do_add_adapter函数。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_detect(adap, driver);
/* Let legacy drivers scan this bus for matching devices */
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函数,接着判断i2c_driver中是否有driver->attach_adapter成员,如果有就执行该函数。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;
if (!driver->detect || !address_list)
return 0;
/* Stop here if the classes do not match */
if (!(adapter->class & driver->class))
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;
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 (unlikely(err))
break;
}
kfree(temp_client);
return err;
}
代码26~27行,先判断i2c_driver是否有detect函数与address_list成员。
代码30~31行,检查driver->class是否与adapter->class相容。
代码34~37行,分配一个临时的i2c_client结构。
代码39~46行,遍历i2c_driver->address_list,对每个地址执行i2c_detect_address(temp_client,driver)函数,该函数将与地址的从设备通信。
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 */
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);
else
dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
info.type, info.addr);
}
return 0;
}
代码60~65行,判断从设备地址是否有效。
代码68~69行,判断该地址是否已经被使用。
代码72~73行,做初始化的设备侦测。i2c_default_probe会与地址进行简单的通信。
代码第75~83行,调用i2c_driver->detect函数。
代码第85~96行,如果i2c_driver->detect调用返回成功,则会调用i2c_new_device(adapter,&info)创建设备i2c_client与device设备模型,这个之前在i2c_adapter中已讲。
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);
int i2c_read_register(struct i2c_client *client, unsigned char reg,unsigned int len, unsigned char *data);
int i2c_write_register(struct i2c_client *client, unsigned int len,unsigned char const *data);
int i2c_read_register(struct i2c_client *client, u16 addr, u16 *val);
int i2c_write_register(struct i2c_client *client, u16 addr, u16 val);
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs,intnum)
内核通过i2c_adapter的成员函数master_xfer而封装的传输函数。
其中参数i2c_adapter,可以通过i2c_client->adapter得到。
对于传输多位数据,如要读取32位的数据,读取的寄存器的开始地址为0x00,则0x00寄存器的值会存在(u8)buf[0]中,0x01寄存器的值会存在(u8)buf[1]中,依次类推。
下面是两个用i2c_transfe实现的读写从设备寄存器的函数。
int i2c_read_register(struct i2c_client *client, unsigned char reg,unsigned int len, unsigned char *data);
int i2c_write_register(struct i2c_client *client, unsigned int len,unsigned char const *data);
而对16地位的16位寄存器读取与写入16位的值,应该清楚I2C传输的规定,数据是从高位开始传递的,所以不管是写入的地址或值还是读取的值,其都是从高位开始的。可以下面的方法。
int i2c_read_register(struct i2c_client *client, u16 addr, u16 *val);
int i2c_write_register(struct i2c_client *client, u16 addr, u16 val);
int i2c_master_send(const struct i2c_client *client,constchar*buf,intcount);
inti2c_master_recv(const struct i2c_client *client,char*buf,intcount);
通过i2c_transfer封装的发送与接收函数。发送与接收都只是一个i2c_msg信息,一个i2c_msg表示一次不变向的传输过程。其中从设备的地址保存client->addr,其默认为10位地址(10位地址的使用不会影响7位地址的使用)。
int i2c_check_functionality(struct i2c_adapter *adap, u32 func)
检查i2c_adapter是否支持func功能。
一般I2C的操作更多的是读写从设备的寄存器的数据。向寄存器数据中写数据只需要一个i2c_msg,该i2c_msg->len的等于2(7位从设备地址,8位寄存器地址,8位数据的形式),一个是写的寄存器地址,一个是向寄存器写的数据。向寄存器读数据则需要两个i2c_msg,每个i2c_msg->len为1,一个是寄存器的地址,一个读取的数据。
由于SMBus与I2C的兼容性。上面的操作可以用内核提供的SMBus的接口完成。
s32 i2c_smbus_read_byte_data(const struct i2c_client *client,
u8 command);
s32 i2c_smbus_write_byte_data(const struct i2c_client *client,
u8 command, u8 value);
s32 i2c_smbus_read_word_data(const struct i2c_client *client,
u8 command);
s32 i2c_smbus_write_word_data(const struct i2c_client *client,
u8 command, u16 value);
其中command对应寄存器地址,写函数的参数value为写入寄存器的值,写入成功返回0,否则返回错误值;读函数的返回值就是读取的数据。
上面的函数如果i2c_adapter实现了smbus_xfer成员函数,那么就会调用该函数;如果没有,则会用master_xfer模拟smbus_xfer完成传输。所以在没有实现smbus_xfer成员函数的情况下,调用i2c_smbus的相关接口函数会比使用i2c_transfer的执行效率慢。
i2c_smbus_xxx_word_data读出字的数据的高8位与低8位是相反的,可使用swab16(u16)转换过来。