现在的位置: 首页 > 综合 > 正文

基于at91rm9200的i2c分析(DS1307实时时钟芯片)

2013年10月02日 ⁄ 综合 ⁄ 共 5668字 ⁄ 字号 评论关闭

board-ek.c
构造i2c_board_info结构体
static struct i2c_board_info __initdata ek_i2c_devices[] = {
    {
        I2C_BOARD_INFO("ds1307", 0x68),
    },
};

at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));->
        i2c_register_board_info(0, devices, nr_devices);->
            将i2c_board_info添加到__i2c_board_list,总线0
            struct i2c_devinfo    *devinfo;
            devinfo->busnum = busnum;
            devinfo->board_info = *info;
            list_add_tail(&devinfo->list, &__i2c_board_list);
        注册at91rm9200_twi_device平台device
        platform_device_register(&at91rm9200_twi_device);
    
static struct platform_device at91rm9200_twi_device = {
    .name        = "at91_i2c",
    .id        = -1,
    .resource    = twi_resources,
    .num_resources    = ARRAY_SIZE(twi_resources),
};

i2c-at91.c
static struct platform_driver at91_i2c_driver = {
    .probe        = at91_i2c_probe,
    .remove        = __devexit_p(at91_i2c_remove),
    .suspend    = at91_i2c_suspend,
    .resume        = at91_i2c_resume,
    .driver        = {
        .name    = "at91_i2c",
        .owner    = THIS_MODULE,
    },
};
    注册平台driver
    platform_driver_register(&at91_i2c_driver);
当发现device链表有与”at91_i2c“同名的device就调用at91_i2c_probe

at91_i2c_probe->
        构造adapter
        struct i2c_adapter *adapter;
        snprintf(adapter->name, sizeof(adapter->name), "AT91");
        adapter->algo = &at91_algorithm;    /* 通信算法 */
        
        clk_enable(twi_clk);        /* enable peripheral clock */
        at91_twi_hwinit();        /* initialize TWI controller */
        at91_twi_hwinit();        /* initialize TWI controller */
        注册adapter
        i2c_add_numbered_adapter(adapter)->
            i2c_register_adapter(adap)->
                    device_register(&adap->dev);
                    /* create pre-declared device nodes */
                    i2c_scan_static_board_info(adap);->
                        list_for_each_entry(devinfo, &__i2c_board_list, list)
                            如果busnum相等则调用i2c_new_device
                            if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))->
                                构造client
                                struct i2c_client    *client;
                                client->adapter = adap;
                                /* 检查设备地址是否有效 */
                                i2c_check_client_addr_validity(client);
                                /* 检查地址是否被占用 */
                                i2c_check_addr_busy(adap, client->addr);
                                注册device
                                device_register(&client->dev);

i2c-dev.c
i2c_dev_init->
    申请设备号,并创建cdev,初始化cdev
    register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
    创建class:/sys/class/i2c-dev
    i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
    注册i2c_driver
    i2c_add_driver(&i2cdev_driver);->
        i2c_register_driver(THIS_MODULE, driver);->
            注册driver
            driver_register(&driver->driver);
            在链表i2c_bus_type中遍历每一个device,对每一个device调用__process_new_driver
            bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
__process_new_driver->
    i2c_do_add_adapter(data, to_i2c_adapter(dev))
        调用driver的attach_adapter函数,即i2cdev_attach_adapter
        driver->attach_adapter(adap)->
            /* 构造i2c_dev */
            i2c_dev = get_free_i2c_dev(adap);->
                    /* 将i2c_dev添加到i2c_dev_list */
                    list_add_tail(&i2c_dev->list, &i2c_dev_list);
            /* 在/dev/目录下创建设备节点i2c-0 */
            i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,    MKDEV(I2C_MAJOR, adap->nr), NULL, "i2c-%d", adap->nr);
这样我们就可以通过i2cdev_fops来操作i2c设备了
static const struct file_operations i2cdev_fops = {
    .owner        = THIS_MODULE,
    .llseek        = no_llseek,
    .read        = i2cdev_read,
    .write        = i2cdev_write,
    .unlocked_ioctl    = i2cdev_ioctl,
    .open        = i2cdev_open,
    .release    = i2cdev_release,
};    

我们也可以不通过/dev/i2c-0这种操作方式,单独实现特定的i2c_driver和i2c_client
rtc-ds1307.c

static const struct i2c_device_id ds1307_id[] = {
    { "ds1307", ds_1307 },
    { "ds1337", ds_1337 },
    { "ds1338", ds_1338 },
    { "ds1339", ds_1339 },
    { "ds1388", ds_1388 },
    { "ds1340", ds_1340 },
    { "ds3231", ds_3231 },
    { "m41t00", m41t00 },
    { "rx8025", rx_8025 },
    { }
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);

static struct i2c_driver ds1307_driver = {
    .driver = {
        .name    = "rtc-ds1307",
        .owner    = THIS_MODULE,
    },
    .probe        = ds1307_probe,
    .remove        = __devexit_p(ds1307_remove),
    .id_table    = ds1307_id,
};

i2c_add_driver(&ds1307_driver)->
    i2c_register_driver(THIS_MODULE, driver)->
        driver->driver.bus = &i2c_bus_type;
        注册driver
        driver_register(&driver->driver)->
            检查driver是否已存在
            driver_find(drv->name, drv->bus)->
            bus_add_driver(drv)->
                driver_attach(drv)->
                    遍历drv->bus链表上的每一个device,为每一个device调用__driver_attach
                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)->
__driver_attach(struct device *dev, void *data)->
    driver_match_device(drv, dev))->
        如果总线i2c_bus_type存在match函数则调用match
        drv->bus->match ? drv->bus->match(dev, drv) : 1;
i2c-core.c中定义了i2c_bus_type,同时定义了i2c_device_match函数
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,
};

i2c_device_match(struct device *dev, struct device_driver *drv)->
    匹配i2c_device_id(ds1307_id)里的名称
    i2c_match_id(driver->id_table, client)->
    
如果匹配成功,继续driver_attach->
    driver_probe_device(drv, dev)->
        really_probe(dev, drv)->
            调用i2c_device_probe
            dev->bus->probe(dev)->
                struct i2c_driver *driver = to_i2c_driver(dev->driver)
                调用ds1307_probe
                driver->probe(client, i2c_match_id(driver->id_table, client))->
                    注册rtcdevice
                    ds1307->rtc = rtc_device_register(client->name, &client->dev, &ds13xx_rtc_ops, THIS_MODULE)->
                        注册device
                        device_register(&rtc->dev);
                    
                

        
    
    
    
       

抱歉!评论已关闭.