###1. i2c总线:
i2c是“Inter-IC” bus 的缩写,它是一种广泛应用于低速率通信的简单的总线协议。由于它是一个许可商标, 有些厂商也使用其它的名称(比如”Two-Wire Interface”, TWI) ,i2c只需要两根信号线(时钟线SCL,数据线SDA),大部分i2c设备使用7bit地址,总线速率可达400KHz(高速扩展可达3.4MHz,但很少被使用)。i2c是一条多主机总线,开漏信号被用来在主机之间来进行仲裁,以及在慢速设备之间进行握手及同步时钟。
###2. linux的i2c接口:
linux的i2c接口只支持主机端的通信,i2c接口围绕两种驱动和两种设备来组织,适配器驱动(“Adapter Driver”)用来抽象硬件上的i2c控制器,它绑定到一个物理设备(可能是PCI设备或者平台设备),并为它管理的每一条i2c总线使用一个结构体“i2c_adapter”来表示。而在i2c总线上, 使用结构体”i2c_client”来代表挂接在上面的i2c设备。这些i2c设备都应该绑定到一个结构体“i2c_driver”上以符合linux的驱动模型。有一系列的函数用来进行i2c协议的操作,到目前为止, 只能从任务上下文中使用它们.
linux中i2c驱动框架中,分为总线(BUS)驱动和设备(DEVICE)驱动,总线驱动的职责是为系统中每一个i2c总线实现相应的读写方法,提供给设备驱动来使用,但是总线驱动并不进行任何的通信。设备驱动则是与挂接在i2c总线上的设备进行通讯的驱动,通过i2c总线驱动提供的方法, 设备驱动可以忽略不同的i2c总线控制器的差异。
###3. i2c总线驱动:
在系统开机时, 首先装载总线驱动,一个驱动用于支持一条特定的i2c总线的读写,一个总线驱动通常使用两个数据结构来描述:
- i2c_adapter
- i2c_algorithm
####3.1 i2c_adapter
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; /* 单位为 jiffies */
int retries;
struct device dev;
int nr; /*i2c bus 编号, 若置为-1, 则代表动态分配*/
char name[48];
struct completion dev_released;
struct mutex userspace_clients_lock;
struct list_head userspace_clients;
};
向系统中注册 i2c adpater 可以使用如下api
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
int i2c_add_adapter(struct i2c_adapter *adapter)
这两个api使用任意一个即可, 它们都会自动检查是否需要动态分配总线号还是使用指定的总线号
注销 i2c adapter 可以使用
void i2c_del_adapter(struct i2c_adapter *adap)
####3.2 i2c_algorithm
i2c_algorithm 用于描述i2c总线的传输方法的实现
struct i2c_algorithm {
/* 如果adapter不能支持i2c访问, 则置 master_xfer 为NULL */
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
/* 如果adapter支持SMBus访问, 则设置smbus_xfer, 若 smbus_xfer 为NULL, 则使用I2C访问来模拟SMBus访问 */
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 *); /* 用于查询i2c adapter支持那些function */
};
i2c_adaptrer对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个i2c适配器需要i2c_algorithm提供的通信函数来控制适配器器上产生特定的访问信号,因此在i2c_adapter中包含其使用的i2c_algorithm的指针。
不同的i2c总线控制器,都有各自的 i2c_adapter, 但是若它们的操作方式相同, 则可以共享同一 i2c_algorithm, 例如, 移动设备的SoC上通常集成有多条i2c总线, 但是他们的操作方式是相同的, 因此可以共享同一 i2c_algorithm
####3.3 i2c_msg
i2c_algorithm中的通信函数以 i2c_msg 为通信的基本单位:
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 */
#define I2C_M_NEED_DELAY 0x0020 // add by kfx
#define I2C_M_REG8_DIRECT 0x0040 // add by kfx
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
###4. i2c设备驱动:
####4.1 i2c_client
总线驱动只是实现了对一条总线的读写,与具体的设备进行通信是由i2c设备驱动来进行的,一个i2c的设备驱动由两个模块(i2c_driver 和 i2c_client)来描述:
struct i2c_client {
unsigned short flags;
unsigned short addr; //设备地址
char name[I2C_NAME_SIZE]; //设备名称
struct i2c_adapter * adapter; //设备所在的i2c总线的adapter
struct i2c_driver * driver; //绑定的driver
struct device dev;
int irq; //设备的irq号
struct list_head detected; //用于将同一个i2c_driver所驱动的i2c_client形成链表
};
i2c_client对应于真实的物理设备,每一个i2c设备都需要一个i2c_client来表示
####4.2 i2c_driver
struct i2c_driver {
unsigned int class;
int (* attach_adapter) (struct i2c_adapter *); /* 旧式i2c driver的方法, 不要再使用 */
int (* probe) (struct i2c_client *, const struct i2c_device_id *);
int (* remove) (struct i2c_client *);
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;
int (* detect) (struct i2c_client *, struct i2c_board_info *);
const unsigned short * address_list;
struct list_head clients;
};
i2c_driver对应一个驱动的方法,不对应任何的物理实体
####4.3 i2c_device_id
struct 用于描述i2c_driver和i2c_client匹配的条件
struct i2c_device_id {
char name[I2C_NAME_SIZE]; //该name和i2c_client.name相同,则i2c_client和i2c_driver匹配成功, 进行后续的probe过程
kernel_ulong_t driver_data; //传递给driver的私有数据, 不使用则置0
};
例如
struct i2c_device_id kxtj2_id[] = {
{ "kxtj2", 0, }
{ "kxtj9", 0, }
{} /*空成员, 用于标识结尾*/
};
struct i2c_driver kxtj2_driver = {
.driver = {
.name = "gsensor-kxtj2",
.owner = THIS_MODULE,
},
.id_table = kxtj2_id,
......
}
i2c_driver.id_table 中可以保存多个struct i2c_device_id, 在匹配时, 依次比较其中的每一个struct i2c_device_id, 直到结束或者匹配成功
一个i2c_client只能绑定到一个i2c_driver, 一个i2c_driver可以绑定到多个i2c_client, 当注册一个i2c_client或者i2c_driver时, linux中的i2c bus core会遍历已经注册的i2c_driver或者已注册但是未绑定driver的i2c_client, 当i2c_client和i2c_driver匹配成功后,进行linux driver model的probe过程
利用i2c_driver.id_table 进行匹配是linux i2 core的标准做法, 为了支持ACPI和Open Firmware, 还扩展了 i2c_driver.acpi_match_table 和 i2c_driver.of_match_table, 后续章节将会讲到
####4.4 如何生成i2c_client
i2c总线不具备枚举能力, 因此, 需要使用合适的方式来注册i2c_client, 有多种方式可以实现这一目的
#####4.4.1 使用 i2c_register_board_info() 来注册i2c_clien
如果明确的知道存在哪些i2c设备, 他们的地址以及所连接的总线, 那么,可以使用struct i2c_board_info来描述i2c设备
struct i2c_board_info {
char type[I2C_NAME_SIZE]; //设备名称, 和i2c_driver匹配时需要使用这一名称
unsigned short flags; //用于初始化i2c_client.flag成员
unsigned short addr; //i2c设备的地址
void *platform_data; //i2c设备的私有数据, 自定义
struct dev_archdata *archdata; //用于初始化 i2c_client.dev.archdata
struct device_node *of_node; //指向openfirmware的device node
struct acpi_dev_node acpi_node; //指向ACPI的device node
int irq; //i2c设备的irq号
};
然后使用i2c_register_board_info() 来根据i2c_board_info注册i2c_client (i2c_board_info中最少需要填充 type和addr成员)
int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);
例如:
struct i2c_board_info kxtj2_info[] = {
{
.type = "kxtj2",
.addr = 0x0f,
},
};
struct i2c_device_id kxtj2_id = {
"kxtj2",
0,
};
struct i2c_driver kxtj2_driver = {
.driver = {
.name = "gsensor-kxtj2",
.owner = THIS_MODULE,
},
.id_table = kxtj2_id,
......
}
static int __init kxtj2_init(void) {
i2c_register_board_info(5,kxtj2_info, ARRAY_SIZE(kxtj2_info) );
return i2c_add_driver(kxtj2_driver);
}
module_init(kxtj2_init);
上述的实例代码只是展示i2c_register_board_info()的使用方式, 事实上,作为一种标准的做法, i2c_board_info 应该放在 linux kernel 源码中 /arch 下架构相关的子目录里面的board.c(名称并不固定)文件中定义, 并在MACHINE_START中会间接调用(比module_init的调用过程早)i2c_register_board_info来注册i2c设备, 在linux源码中的(arch/arm/plat-xxx和arch/arm/mach-xxx)中可以找到大量的i2c_client的注册过程
i2c_register_board_info()可以算作是静态初始化i2c_client,通过其注册的i2c_board_info会被存储在链表 __i2c_board_list中, 当对应的i2c总线的driver初始化时(即通过i2c_add_adapter()来注册i2c_adapter时), 或遍历__i2c_board_list, 根据其中的内容来注册i2c_client, 这意味着, i2c_register_board_info()必须先于i2c_add_adapter()被调用, 否则,i2c core将不会去注册i2c_client, 因为i2c_register_board_info()都是在MACHINE_START()中被调用, 早于i2c controller driver的初始化, 因此不会有这一问题, 但若是在i2c device driver中才调用i2c_register_board_info()来注册i2c_client则有可能为时太晚(特别是driver被编译为模块时)
#####4.4.2 使用 i2c_new_device 和 i2c_new_probed_device 创建i2c_client
使用 i2c_register_board_info() 来注册i2c_clien的方式存在诸多限制:
- 必须在MACHINE_STAR()阶段就注册i2c_board_info
- 必须在编译内核时确定i2c总线编号和设备地址
但是如果开发者不确定有哪些i2c设备,有多少i2c总线,就需要自己动态注册i2c_client了
动态注册i2c_client时, 同样需要使用 struct i2c_board_info 来描述i2c设备的相关信息, 然后使用i2c_new_device()来动态注册i2c_client了
i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
例如
struct i2c_board_info kxtj2_info = {
.type = "kxtj2",
.addr = 0x0f,
};
struct i2c_device_id kxtj2_id = {
"kxtj2",
0,
};
struct i2c_driver kxtj2_driver = {
.driver = {
.name = "gsensor-kxtj2",
.owner = THIS_MODULE,
},
.id_table = kxtj2_id,
......
}
static int __init kxtj2_init(void) {
struct i2c_adapter *adapter;
struct i2c_client *client;
/* 请确定此时对应的adapter的的driver已经加载好, 否无法获取adapter*/
if( NULL == ( adapter = i2c_get_adapter(4) ) )
return -1;
if( NULL == ( client = i2c_new_device(adapter, &kxtj2_info) ) )
return -2;
i2c_put_adapter(adapter);
return i2c_add_driver(kxtj2_driver);
}
module_init(kxtj2_init);
如果某个i2c设备作为一种特性, 在同一种产品的不同配置中可能存在,也有可能不存在,又或者它可能使用不同的slave address,那么,可以列出所有可能的地址值,然后使用i2c_new_probed_device()在这些地址上进行probe(), 根据probe的结构, 会动态生成对应的i2c_client
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));
//probe回调函数可以不指定, 使用i2c core默认的函数 i2c_default_probe()
例如, kxtj2可能使用 0x0e和0x0f这两个地址中的一种
struct i2c_board_info kxtj2_info = {
.type = "kxtj2",
.addr = 0x0f, /* 此地址值无用,将使用探测到的地址来替代它*/
};
/* kxtj2可能使用的slave address */
static const unsigned short kxtj2_valid_addr = {
0x0e,
0x0f,
I2C_CLIENT_END,
};
struct i2c_device_id kxtj2_id = {
"kxtj2",
0,
};
struct i2c_driver kxtj2_driver = {
.driver = {
.name = "gsensor-kxtj2",
.owner = THIS_MODULE,
},
.id_table = kxtj2_id,
......
}
static int __init kxtj2_init(void) {
struct i2c_adapter *adapter;
struct i2c_client *client;
/* 请确定此时对应的adapter的的driver已经加载好, 否无法获取adapter*/
if( NULL == ( adapter = i2c_get_adapter(4) ) )
return -1;
if( NULL == ( client = i2c_new_probed_device(adapter, &kxtj2_info, kxtj2_valid_addr, NULL ) ) )
return -2;
i2c_put_adapter(adapter);
return i2c_add_driver(kxtj2_driver);
}
module_init(kxtj2_init);
由于i2c adapter可能在一个即插即用设备上, 它有可能在任何时候被插接在系统上, 这意味着你的i2c设备驱动有可能在i2c总线驱动之前被加载, 这个时候, 在使用i2c_get_adapter的时候将会失败, 因为此时对应的adapter还未被建立起来, 那么在 module_init 里面进行i2c_new_device之类的操作并不安全。为此, 可以将这些操作放在i2c_driver中的.attach_adapter中。
使用 i2c_new_device() 和 i2c_new_probed_device() 这两个函数来创建i2c_client的driver有义务在退出时销毁创建的i2c_client, 可以使用i2c_unregister_device()来注销创建的i2c_client
#####4.4.3 在所有的i2c总线上探测i2c设备
如果你连有多少i2c设备, 挂接在哪一条总线上, 设备地址等信息都一无所知的话, 那你就没办法使用 i2c_register_board_info() 方法和 i 2c_new_device() 的方法来创建i2c_client了(这些方法要求指定i2c总线号)但是,如果你知道通过设备ID来判别设备的话, 那么你还有 i2c_driver.detect() 方法可以使用
int (*detect)(struct i2c_client *, struct i2c_board_info *);
给出设备可能的addr的列表, 并且提供一个detect回掉函数,在i2c_add_driver()时, i2c core会在所有已经注册的i2c总线上, 遍历所有指定的地址, 若检测到有设备存在, 则生成一个临时的i2c_client, 然后回调 i2c_driver.detect() 函数, 在该函数中, device driver需要自行判断是否支持该设备, 若是, 则可以填充i2c_board_info中的相关信息然后返回0, i2c core会根据填充的 i2c_board_info 来调用i2c_new_device() 来正式注册一个i2c_client
例如
struct i2c_device_id kxtj2_id = {
"kxtj2",
0, /* 此地址值无用,将使用探测到的地址来替代它*/
};
static const unsigned short kxtj2_valid_addr[] = {
0x0e,
0x0f,
};
int kxtj2_detect(struct i2c_client *client, struct i2c_board_info *info)
{
unsigned short chip_id = i2c_smbus_read_byte_data(client, 0x00);
/* 如果检测到设备, 至少需要填充info的type域 */
if( 0x09 == chip_id )
info->type = "kxtj2";
else
return -ENODEV;
/* 此函数中不得修改info的type域 */
return 0;
}
struct i2c_driver kxtj2_driver = {
.driver = {
.name = "gsensor-kxtj2",
.owner = THIS_MODULE,
},
.id_table = kxtj2_id
......
.detect = kxtj2_detect,
.address_list = kxtj2_valid_addr,
......
}
module_i2c_driver(kxtj2_driver);
要使用detect的方法, 前提是总线adapter支持该类driver的探测(i2c_adapter->class & i2c_driver->class != 0).
要使用i2c_driver.detect() 回调接口, 需要填充i2c_driver中的address_list域,声明所有需要探测的设备地址,并实现它的detect回调函数。 在i2c_add_driver()时, i2c_core会在所有已经注册的adapter上探测address_list中的所有地址, 探测到存在i2c设备且未绑定driver后, 会调用detect回调函数,在该回调函数中, device driver需要自行判断是否支持该设备, 若是, 则可以填充i2c_board_info中的相关信息然后返回0, i2c core会根据填充的 i2c_board_info 来调用i2c_new_device() 来正式注册一个i2c_client(如果info->type不为空, 则建立一个i2c_client),这一步会为每一个adapter上的每一个detect成功的地址创建一个i2c_client.
使用这一种方法建立的client在driver退出或者所在的i2c bus脱离时会被自动销毁, 该方法比i2c_register_board_info() 方法和 i 2c_new_device() 的方法更为灵活, 但是不如前两种方法快速和安全,应该尽可能使用前两种方法。
#####4.4.4 在用户空间枚举建立
每一个i2c_adapter会在sys文件系统下面建立两个只写的属性文件“new_device”和“delete_device”用来建立和删除i2c设备:
# echo kxtj2 0x0f > /sys/class/i2c-adapter/i2c-5/new_device
# echo 0x0f > /sys/calss/i2c-adapter/i2c-5/delete_device
该方法使用方便, 在某些情况下(缺少相关信息, 方法1和方法2不能使用,而adapter不支持driver的detect)只能使用该方式。
#####4.4.5 使用ACPI的信息来建立i2c_client
在使用ACPI(主要是x86)的平台上, 可以通过ACPI来上报i2c设备信息,那么,linux中提供了 acpi_i2c_register_devices()接口来遍历ACPI信息, 注册i2c_client
void acpi_i2c_register_devices(struct i2c_adapter *adapter)
通常是在i2c adapter的driver的probe过程中调用此接口来注册i2c_client
这一接口事实上还是根据ACPI上报的设备信息,调用i2c_new_device()来注册i2c_client
通过ACPI上报i2c设备信息的系统上, 还可以使用 i2c_driver.acpi_match_table 来进行 i2c_client 和 i2c_driver 的匹配
struct acpi_device_id {
__u8 id[ACPI_ID_LEN];
kernel_ulong_t driver_data;
};
例如
static struct acpi_device_id kxtj2_acpi_match[] = {
{ "kxtj2", 0 },
{ },
};
static struct i2c_driver kxtj2_driver = {
.driver = {
.name = "kxtj2",
.owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(kxtj2_acpi_match),
},
.probe = kxtj2_probe,
.remove = kxtj2_remove,
.id_table = kxtj2_id,
}
i2c_core 先使用 i2c_driver.acpi_match_table进行匹配, 若匹配不成功, 再尝试使用i2c_driver.id_table进行匹配
即使是利用 i2c_driver.acpi_match_table 也需要保证 i2c_driver.id_table 不为空, 当 i2c_driver.probe 或者 i2c_driver.id_table 为空时, i2c_driver.probe 将不会被调用(见 i2c_device_probe() )
#####4.4.6 使用dts信息来建立i2c_client
早期的arm平台上, 都是在MACHINE_START()过程中完成板级设备信息的初始化, 因此, “arch/arm/plat-xxx“和”arch/arm/mach-xxx”中存在大量的垃圾代码, 后续arm平台引入了open firmware的dts(Device Tree Source)的方式来描述板级设备/资源信息, 同样的, i2c设备也能使用dts来描述, 例如,G-sensor kxtj2在dtsi中的描述如下
i2c@f9925000 { /* BLSP-1 QUP-3 */
kionix@f {
compatible = "kionix,kxtj9";
reg = <0x0f>;
interrupt-parent = <&msmgpio>;
interrupts = <81 0x2>;
vdd-supply = <&pm8110_l19>;
vio-supply = <&pm8110_l14>;
kionix,min-interval = <5>;
kionix,init-interval = <200>;
kionix,axis-map-x = <1>;
kionix,axis-map-y = <0>;
kionix,axis-map-z = <2>;
kionix,g-range = <2>;
kionix,negate-x;
kionix,negate-y;
kionix,negate-z;
kionix,res-12bit;
};
};
其中“kionix, xxx”是设备特定的信息,只关注i2c设备的相关信息
i2c@f9925000 { /* BLSP-1 QUP-3 */
kionix@f {
compatible = "kionix,kxtj2";
reg = <0x0f>;
};
};
dts信息描述了kxtj2的i2c地址为0x0f
Open Firmware 提供了一个接口用于根据dts信息来注册 i2c_client
void of_i2c_register_devices(struct i2c_adapter *adap);
该接口一般由i2c controller driver来调用, 来根据dts信息为i2c bus上的i2c设备注册 i2c_client
通过Open firmware 的dts上报的i2c设备, 其driver还可以使用 i2c_driver.of_match_table 来进行i2c_client 和 i2c_driver 的匹配
struct of_device_id
{
char name[32];
char type[32];
char compatible[128];
const void *data;
};
例如
static struct of_device_id kxtj2_match_table[] = {
{ .compatible = "kionix,kxtj2", },
{ },
};
static struct i2c_driver kxtj2_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
.of_match_table = kxtj2_match_table,
},
.probe = kxtj2_probe,
.remove = kxtj2_remove,
.id_table = kxtj2_id,
};
i2c_core 先使用 i2c_driver.of_match_table进行匹配,若匹配不成功, 则尝试使用i2c_driver.acpi_match_table进行匹配, 若匹配不成功, 再尝试使用i2c_driver.id_table进行匹配
即使是利用 i2c_driver.of_match_table 也需要保证 i2c_driver.id_table 不为空, 当 i2c_driver.probe 或者 i2c_driver.id_table 为空时, i2c_driver.probe 将不会被调用(见 i2c_device_probe() )
####4.5 i2c client data
i2c device driver可以支持多个driver, 有时在driver中需要为某个device维护一份private data, 则可以使用i2c client data, i2c client data 本质是在 i2c_client->dev->p 中保存一个指针, 指向一块数据
如下两个接口可用于 set/get i2c client data
void i2c_set_clientdata(struct i2c_client *dev, void *data);
void *i2c_get_clientdata(const struct i2c_client *dev);
####4.6 i2c 传输的接口
在 i2c device driver 中,一定会对i2c device 发起读写操作, 可以例如 i2c core 提供的接口
i2c core提供了最基本的传输接口, 可以完成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);
####4.7 SMBus 传输接口
i2c core同样还提供了接口, 用于完成SMBus命令操作
最基本的SMBus传输接口
s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
union i2c_smbus_data *data)
在此基础上, 还封装了如下的接口, 用于完成不同类型的SMBus传输操作
s32 i2c_smbus_read_block_data(const struct i2c_client *client, u8 command, u8 *values)
s32 i2c_smbus_read_byte(const struct i2c_client *client);
s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command)
s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, u8 *values)
s32 i2c_smbus_read_word_data(const struct i2c_client *client, u8 command)
s32 i2c_smbus_write_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values)
s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value)
s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value)
s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values)
s32 i2c_smbus_write_word_data(const struct i2c_client *client, u8 command,u16 value)
####4.8 获取对应i2c总线的adapter
某些操作需要指定 i2c_adapter, 根据i2c_client可以获取对应的adapter( i2c_client->adapter)
还使用如下api根据总线号获取adapter
struct i2c_adapter *i2c_get_adapter(int nr)
释放对i2c adapter的引用
void i2c_put_adapter(struct i2c_adapter *adap)
i2c_get_adapter() / i2c_put_adapter() 应成对出现
有时候, 需要根据 i2c_adapter.dev 的地址, 取得i2c_adapter指针, 可以使用如下的两种接口
struct i2c_adapter *i2c_verify_adapter(struct device *dev)
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
####4.9 检查i2c adapter支持的function
如下api可以获取某个i2c adapter所支持的function
u32 i2c_get_functionality(struct i2c_adapter *adap)
如下api可以检查某个i2c adapter是否支持所给的function
int i2c_check_functionality(struct i2c_adapter *adap, u32 func)