一. I2C设备的定义及其添加过程
1.1 数据结构
include/linux/i2c.h:
drivers/i2c/i2c-core.h:
1.2 全局变量
drivers/i2c/i2c-core.h:
全局变量的初始化,在driver/i2c/i2c-boardinfo.c中
1.3 I2C设备的定义
在arch/arm/mach-s3c64xx/mach-smdk6410.c中,定义了I2C的设备
其中 #define I2C_BOARD_INFO(dev_type, dev_addr) \
.type = dev_type, .addr = (dev_addr)
.type 是name
.addr 是设备在i2c上的地址
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
在driver/i2c/i2c-boardinfo.c中:
1.4 I2C设备的添加过程
s3c24xx_i2c_probe
--> i2c_add_numbered_adapter
--> i2c_register_adapter
--> i2c_scan_static_board_info
--> i2c_new_device
i2c设备的添加过程是随着i2c控制器的添加而添加的,这个在下一篇中详细说一下,这儿就省了!
二. I2C设备驱动的注册过程
这儿以ov9650为例说明一下,(为什么呢? 因为ok6410上面没有其它的i2c设备了!)
drivers/media/video/samsung/fimc/ov965x.c
ov965x_init
--> i2c_add_driver
ov965x_init
--> i2c_add_driver
--> i2c_device_probe
driver/i2c/i2c-core.c
下面接着分析
三. I2C设备驱动的写过程
i2c_device_probe
- - > ov965x_probe
i2c_device_probe
- - > ov965x_probe
--> i2c_smbus_write_byte_data
driver/i2c/i2c-core.c
i2c_device_probe
- - > ov965x_probe
--> i2c_smbus_write_byte_data
--> i2c_smbus_xfer_emulated
driver/i2c/i2c-core.c
i2c_device_probe
- - > ov965x_probe
--> i2c_smbus_write_byte_data
--> i2c_smbus_xfer_emulated
--> i2c_transfer
driver/i2c/i2c-core.c
注: ret
=
adap
-
>
algo
-
>
master_xfer
(
adap
,
msgs
,
num
)
;
是i2c控制器的数据传输函数,下一篇分析
1.1 数据结构
include/linux/i2c.h:
- 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; //
- };
- struct i2c_devinfo {
- struct list_head list; //i2c设备列表头
- int busnum; //i2c总线并不是只有一条
- struct i2c_board_info board_info; //
- };
1.2 全局变量
drivers/i2c/i2c-core.h:
- extern struct rw_semaphore __i2c_board_lock; //
- extern struct list_head __i2c_board_list; //
- extern int __i2c_first_dynamic_bus_num; //
- DECLARE_RWSEM(__i2c_board_lock); //读写锁
- EXPORT_SYMBOL_GPL(__i2c_board_lock);
-
- LIST_HEAD(__i2c_board_list); //双向链表
- EXPORT_SYMBOL_GPL(__i2c_board_list);
-
- int __i2c_first_dynamic_bus_num;
- EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
在arch/arm/mach-s3c64xx/mach-smdk6410.c中,定义了I2C的设备
- static struct i2c_board_info i2c_devs0[] __initdata = {
- { I2C_BOARD_INFO("ov965x", 0x30), }, // gjl
- };
-
- static struct i2c_board_info i2c_devs1[] __initdata = {
- { I2C_BOARD_INFO("24c128", 0x57), }, /* Samsung S524AD0XD1 */
- };
.type = dev_type, .addr = (dev_addr)
.type 是name
.addr 是设备在i2c上的地址
在arch/arm/mach-s3c64xx/mach-smdk6410.c中
- static void __init smdk6410_machine_init(void)
- {
- i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); //将bus 0上的设备添加到i2c的设备链表中
- i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); //将bus 1上的设备添加到i2c的设备链表中
- }
- int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
- {
- int status;
-
- down_write(&__i2c_board_lock);
-
- 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);
-
- devinfo->busnum = busnum; //新建一个i2c_devinfo结构体,初始化之后
- devinfo->board_info = *info; //初始化后,插入到i2c设备链表的尾部
- list_add_tail(&devinfo->list, &__i2c_board_list); //在全局变量i2c_board_list中添加新的设备
- }
-
- up_write(&__i2c_board_lock);
-
- return status;
- }
-
s3c24xx_i2c_probe
--> i2c_add_numbered_adapter
--> i2c_register_adapter
--> i2c_scan_static_board_info
--> i2c_new_device
i2c设备的添加过程是随着i2c控制器的添加而添加的,这个在下一篇中详细说一下,这儿就省了!
二. I2C设备驱动的注册过程
这儿以ov9650为例说明一下,(为什么呢? 因为ok6410上面没有其它的i2c设备了!)
drivers/media/video/samsung/fimc/ov965x.c
- static __init int ov965x_init(void)
- {
- return i2c_add_driver(&ov965x_i2c_driver);
- }
- module_init(ov965x_init)
--> i2c_add_driver
- static inline int i2c_add_driver(struct i2c_driver *driver)
- {
- return i2c_register_driver(THIS_MODULE, driver);
- }
-
- 在driver/i2c/i2c-core.c中
- int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
- {
- driver->driver.owner = owner;
- driver->driver.bus = &i2c_bus_type;
- res = driver_register(&driver->driver); //注册driver并进入I2C的probe函数
- INIT_LIST_HEAD(&driver->clients);
- //对i2c上的每一个设备执行一次__process_new_driver
- i2c_for_each_dev(driver, __process_new_driver); //但__process_new_driver好像什么事也没有干
- return 0;
- }
- EXPORT_SYMBOL(i2c_register_driver);
ov965x_init
--> i2c_add_driver
--> i2c_device_probe
driver/i2c/i2c-core.c
- static int i2c_device_probe(struct device *dev)
- {
- struct i2c_client *client = i2c_verify_client(dev); //这儿己经是ov965x的dev了,己经得到dev->addr=0x30
- struct i2c_driver *driver;
- int status;
-
- driver = to_i2c_driver(dev->driver);
- client->driver = driver;
- if (!device_can_wakeup(&client->dev))
- device_init_wakeup(&client->dev, client->flags & I2C_CLIENT_WAKE);
- status = driver->probe(client, i2c_match_id(driver->id_table, client)); //开始调用具体设备的probe
- return status;
- }
三. I2C设备驱动的写过程
i2c_device_probe
- - > ov965x_probe
- static int ov965x_probe(struct i2c_client *c, const struct i2c_device_id *id)
- {
- ov965x_data.client = c;
- s3c_fimc_register_camera(&ov965x_data); //向fimc注册
- for (i = 0; i < OV965X_INIT_REGS; i++) { //通过i2c写ov9650的寄存器
- ret = i2c_smbus_write_byte_data(c, OV965X_init_reg[i].subaddr, OV965X_init_reg[i].value);
- }
- return 0;
- }
i2c_device_probe
- - > ov965x_probe
--> i2c_smbus_write_byte_data
driver/i2c/i2c-core.c
- s32 i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value)
- {
- union i2c_smbus_data data;
- data.byte = value;
- return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
- I2C_SMBUS_WRITE, command, I2C_SMBUS_BYTE_DATA, &data);
- }
-
- 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)
- {
- flags &= I2C_M_TEN | I2C_CLIENT_PEC;
- i2c_smbus_xfer_emulated(adapter, addr, flags, read_write, command, protocol, data);
- }
i2c_device_probe
- - > ov965x_probe
--> i2c_smbus_write_byte_data
--> i2c_smbus_xfer_emulated
driver/i2c/i2c-core.c
- static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
- unsigned short flags,
- char read_write, u8 command, int size,
- union i2c_smbus_data *data)
- {
- unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
- unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
- int num = read_write == I2C_SMBUS_READ ? 2 : 1;
- struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
- { addr, flags | I2C_M_RD, 0, msgbuf1 }
- };
-
- msgbuf0[0] = command;
- switch (size) {
- case I2C_SMBUS_BYTE_DATA:
- msg[0].len = 2;
- msgbuf0[1] = data->byte;
- break;
- }
-
- status = i2c_transfer(adapter, msg, num); //把要传输的信息组装成msg,进行传输
- //i==0 && I2C_SMBUS_READ
- }
i2c_device_probe
- - > ov965x_probe
--> i2c_smbus_write_byte_data
--> i2c_smbus_xfer_emulated
--> i2c_transfer
driver/i2c/i2c-core.c
- int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
- {
- unsigned long orig_jiffies;
- int ret, try;
- if (in_atomic() || irqs_disabled()) {
- ret = i2c_trylock_adapter(adap);
- if (!ret)
- return -EAGAIN;
- } else
- i2c_lock_adapter(adap); //加把锁
-
- orig_jiffies = jiffies;
- for (ret = 0, try = 0; try <= adap->retries; try++) { //如果传输失败,则重试adap->retries次
- ret = adap->algo->master_xfer(adap, msgs, num); //传输函数,在文件i2c-s3c2410.c中
- if (ret != -EAGAIN)
- break;
- if (time_after(jiffies, orig_jiffies + adap->timeout)) //如果超时了,不管成不成功立即返回
- break;
- }
- i2c_unlock_adapter(adap); //unlock
- return ret;
- }