S3C6410使用---25 I2C设备驱动分析

来源:互联网 发布:知乎 爬虫 加载 编辑:程序博客网 时间:2024/06/01 10:59

注:

转自:
http://www.programgo.com/article/83144546859/;jsessionid=0BE6120516C6BEFFEA6CE4410474380D

一. 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;                             // };drivers/i2c/i2c-core.h: 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;       //全局变量的初始化,在driver/i2c/i2c-boardinfo.c中 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);

1.3 I2C设备的定义
在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 */};其中 #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中 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的设备链表中}在driver/i2c/i2c-boardinfo.c中: 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;}

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 static __init int ov965x_init(void){    return i2c_add_driver(&ov965x_i2c_driver);}module_init(ov965x_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; }

注: ret = adap - > algo - > master_xfer ( adap , msgs , num ) ; 是i2c控制器的数据传输函数,下一篇分析

0 0
原创粉丝点击