在i2c设备端,驱动开发的主要工作和平台总线一样:构建设备对象和驱动对象,我用的开发板上的i2c总线上挂接的设备是mpu6050,接下来我就以我的板子为例,讨论如何编写i2c设备端的驱动。
同样这里的设备对象也可以使用三种方式构建:平台文件,模块和设备树。
本文采用设备树的方式构建设备对象,我们可以参考内核文档"Documentations/devicetree/bindings/i2c/i2c-s3c2410.txt"以及设备树中的样板来编写我们的设备树节点,** 我们在设备树中可不会写mpu6050内部寄存器的地址,因为这些寄存器地址SoC看不到**。
/{
109 i2c@138B0000 {
110 #address-cells = <1>;
111 #size-cells = <0>;
112 samsung,i2c-sda-delay = <100>;
113 samsung,i2c-max-bus-freq = <20000>;
114 pinctrl-0 =<&i2c5_bus>;
115 pinctrl-names="default";
116 status="okay";
117 mpu6050@68{
118 compatible="invensense,mpu6050";
119 reg=<0x68>;
120 };
121 };
/
--109-->即我们SoC上的i2c控制器的地址
--116-->这个一定要okay,其实是对"./arch/arm/boot/dts/exynos4.dtsi +387"处的status = "disabled"的重写,相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写
--117-->设备子节点,/表示板子,它的子节点node1表示SoC上的某个控制器,控制器中的子节点node2表示挂接在这个控制器上的设备(们)。68即是设备地址。
--118-->这个属性就是我们和驱动匹配的钥匙,一个字符都不能错
--119-->这个属性是从设备的地址,我们可以通过查阅手册"MPU-6050_DataSheet_V3_4"得到
写了这个设备节点,内核就会为我们在内核中构造一个i2c_client对象并挂接到i2c总线对象的设备链表中以待匹配,这个设备类如下
//include/linux/i2c.h 217 struct i2c_client { 218 unsigned short flags; /* div., see below */ 219 unsigned short addr; /* chip address - NOTE: 7bit */ 220 /* addresses are stored in the */ 221 /* _LOWER_ 7 bits */ 222 char name[I2C_NAME_SIZE]; 223 struct i2c_adapter *adapter; /* the adapter we sit on */ 224 struct device dev; /* the device structure */ 225 int irq; /* irq issued by device */ 226 struct list_head detected; 227 };--219-->设备地址
--223-->表示这个client从属的i2c主机对应的adapter对象,驱动方法中使用这个指针发送数据
--224-->表示这是一个device
--225-->中断使用的中断号
--226-->将所有i2c_client连在一起的节点
和平台总线类似,i2c驱动对象使用i2c_driver结构来描述,所以,编写一个i2c驱动的本质工作就是构造一个i2c_driver对象并将其注册到内核。我们先来认识一下这个对象
//include/linux/i2c.h 161 struct i2c_driver { 162 unsigned int class; 167 int (*attach_adapter)(struct i2c_adapter *) __deprecated; 170 int (*probe)(struct i2c_client *, const struct i2c_device_id *); 171 int (*remove)(struct i2c_client *); 174 void (*shutdown)(struct i2c_client *); 175 int (*suspend)(struct i2c_client *, pm_message_t mesg); 176 int (*resume)(struct i2c_client *); 183 void (*alert)(struct i2c_client *, unsigned int data); 188 int (*command)(struct i2c_client *client, unsigned int cmd, void *arg); 190 struct device_driver driver; 191 const struct i2c_device_id *id_table; 194 int (*detect)(struct i2c_client *, struct i2c_board_info *); 195 const unsigned short *address_list; 196 struct list_head clients; 197 };