i2c subsystem 的个人总结

i2c subsystem的故事还要从很久以前说起,那是一个混沌初开的年代......
1、板子初始化
arch/arm/mach-msm/board-msm7x30.c
 static void __init msm7x30_init(void)
{
......
(1) platform_add_devices(devices, ARRAY_SIZE(devices));
......
(2) msm_device_i2c_init();
    msm_device_i2c_2_init();
......
(3) i2c_register_board_info(4 /* QUP ID */, msm_camera_boardinfo,
         ARRAY_SIZE(msm_camera_boardinfo));

......
}
(1) 在此处注册了很多的platform_device devices[],在这一堆的platform_devices中有
msm_device_i2c,
msm_device_i2c_2,
这样两个设备(具体的区别还没有弄清楚,有可能是该板子有两条i2c总线),它们其实就是很容易被人们遗忘的i2c controler,它们被当作platform_device在板子初始化时进行注册。
platform_device的注册过程不详细讲述了,只讲一下最重要的两部match和probe:
a、match
drivers/base/base.h
120 static inline int driver_match_device(struct device_driver *drv,
  121               struct device *dev)
  122 {
)>123   return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  124 }  
call bus->match
671 static int platform_match(struct device *dev, struct device_driver *drv)
   672 {
   673   struct platform_device *pdev = to_platform_device(dev);
   674   struct platform_driver *pdrv = to_platform_driver(drv);
   675
   676   /* match against the id table first */
   677   if (pdrv->id_table)
   678     return platform_match_id(pdrv->id_table, pdev) != NULL;
   679
   680   /* fall-back to driver name match */
   681   return (strcmp(pdev->name, drv->name) == 0);
   682 }
首先看platform_driver有没有定义id_table,有的话:
644 static const struct platform_device_id *platform_match_id(
   645       const struct platform_device_id *id,
   646       struct platform_device *pdev)
   647 {
   648   while (id->name[0]) {
   649     if (strcmp(pdev->name, id->name) == 0) { platform_driver有可能支持多个platform_device,所以可能会有多个platform_device_id项
   650       pdev->id_entry = id;
   651       return id;
   652     }
   653     id++;
   654   }
   655   return NULL;
   656 }
比较platform_device->name和platform_driver->id_entry->name,否则
platform_device->name和device_driver->name
b、probe
static int really_probe(struct device *dev, struct device_driver *drv)
120   if (dev->bus->probe) {
  121     ret = dev->bus->probe(dev);
  122     if (ret)
  123       goto probe_failed;
  124   } else if (drv->probe) {
  125     ret = drv->probe(dev);
  126     if (ret)
  127       goto probe_failed;
  128   }
这里先看能不能call bus->probe,不能则call devices_driver->probe
483 int platform_driver_register(struct platform_driver *drv)
   484 {
   485   drv->driver.bus = &platform_bus_type;
   486   if (drv->probe)
'> 487     drv->driver.probe = platform_drv_probe;
   488   if (drv->remove)
   489     drv->driver.remove = platform_drv_remove;
   490   if (drv->shutdown)
   491     drv->driver.shutdown = platform_drv_shutdown;
}> 492
   493   return driver_register(&drv->driver);
   494 }
486和487
先看有没有platform_driver->probe,有就对device_driver->probe赋值platform_drv_probe,在上面调用devices_driver->probe实际就是调用platform_drv_probe,而platform_drv_probe又会调用platform_driver->probe,这个probe是用户写的具体设备驱动的probe。但是在此时还不会去调用driver的probe,因为现在还没有platform_driver模块被加载,
板子初始化函数继续执行。
(2)msm_device_i2c_init();
static void __init msm_device_i2c_init(void)
{
   if (msm_gpios_request(msm_i2c_gpios_hw, ARRAY_SIZE(msm_i2c_gpios_hw)))
     pr_err("failed to request I2C gpios/n");
 
   msm_device_i2c.dev.platform_data = &msm_i2c_pdata;
}
主要是gpio的申请和i2c controler 平台数据的赋值。
(3)i2c_register_board_info(4 /* QUP ID */, msm_camera_boardinfo,
         ARRAY_SIZE(msm_camera_boardinfo));
这个函数主要是把i2c 的外围设备信息结构体struct ic2_board_info 分装进struct i2c_devinfo结构,再把这个结构放到__i2c_board_list这个链表上。
该函数的第一个参数其实是该i2c 设备所属的adapter的编号,不同的adapter使用的低层i2c通信协议算法可能不一样。

2、i2c controler driver 的加载过程
drivers/i2c/busses/i2c-msm.c 该文件就是i2c controler的驱动程序。
780 static struct platform_driver msm_i2c_driver = {
  781   .probe    = msm_i2c_probe,
  782   .remove   = msm_i2c_remove,
  783   .suspend  = msm_i2c_suspend,
  784   .resume   = msm_i2c_resume,
  785   .driver   = {
  786     .name = "msm_i2c",
  787     .owner  = THIS_MODULE,
  788   },
  789 };
}>790
  791 /* I2C may be needed to bring up other drivers */
  792 static int __init
  793 msm_i2c_init_driver(void)
  794 {
  795   return platform_driver_register(&msm_i2c_driver);
  796 }
platform_driver_register(&msm_i2c_driver) 的过程和platform_device_register的过程很相似,主要两部还是match和probe,不过这回platform_bus_type上已经有设备了,它回去probe设备,并最终调用platform_driver的probe函数msm_i2c_probe。我们来看一看该函数做了些什么。
static int
msm_i2c_probe(struct platform_device *pdev)
{
......
    mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!mem) {
        dev_err(&pdev->dev, "no mem resource?/n");
        return -ENODEV;
    }
    irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if (!irq) {
        dev_err(&pdev->dev, "no irq resource?/n");
        return -ENODEV;
    }

    ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
            pdev->name);
    if (!ioarea) {
        dev_err(&pdev->dev, "I2C region already claimed/n");
        return -EBUSY;
    }
    clk = clk_get(&pdev->dev, "i2c_clk");
    if (IS_ERR(clk)) {
        dev_err(&pdev->dev, "Could not get clock/n");
        ret = PTR_ERR(clk);
        goto err_clk_get_failed;
    }

    pdata = pdev->dev.platform_data;
    if (!pdata) {
        dev_err(&pdev->dev, "platform data not initialized/n");
        ret = -ENOSYS;
        goto err_clk_get_failed;
    }
    if (!pdata->msm_i2c_config_gpio) {
        dev_err(&pdev->dev, "config_gpio function not initialized/n");
        ret = -ENOSYS;
        goto err_clk_get_failed;
    }
    /* We support frequencies upto FAST Mode(400KHz) */
    if (pdata->clk_freq <= 0 || pdata->clk_freq > 400000) {
        dev_err(&pdev->dev, "clock frequency not supported/n");
        ret = -EIO;
        goto err_clk_get_failed;
    }

以上的代码不用说了,就是在获取配置i2c controler的资源。
分配了一个struct msm_i2c_dev的i2c controler的结构体,里面都是i2c controler的资源,以方便以后使用

    dev = kzalloc(sizeof(struct msm_i2c_dev), GFP_KERNEL);
    if (!dev) {
        ret = -ENOMEM;
        goto err_alloc_dev_failed;
    }

    dev->dev = &pdev->dev;
    dev->irq = irq->start;
    dev->clk = clk;
    dev->pdata = pdata;
    dev->base = ioremap(mem->start, (mem->end - mem->start) + 1);
    if (!dev->base) {
        ret = -ENOMEM;
        goto err_ioremap_failed;
    }

    dev->one_bit_t = USEC_PER_SEC/pdata->clk_freq;
    spin_lock_init(&dev->lock);
    platform_set_drvdata(pdev, dev); //pdev->dev->p->driver_data = dev(struct msm_i2c_dev)

    clk_enable(clk);

    if (pdata->rmutex) {
        struct remote_mutex_id rmid;
        rmid.r_spinlock_id = pdata->rsl_id;
        rmid.delay_us = 10000000/pdata->clk_freq;
        if (remote_mutex_init(&dev->r_lock, &rmid) != 0)
            pdata->rmutex = 0;
    }
    /* I2C_HS_CLK = I2C_CLK/(3*(HS_DIVIDER_VALUE+1) */
    /* I2C_FS_CLK = I2C_CLK/(2*(FS_DIVIDER_VALUE+3) */
    /* FS_DIVIDER_VALUE = ((I2C_CLK / I2C_FS_CLK) / 2) - 3 */
    i2c_clk = 19200000; /* input clock */
    fs_div = ((i2c_clk / pdata->clk_freq) / 2) - 3;
    hs_div = 3;
    clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff);
    writel(clk_ctl, dev->base + I2C_CLK_CTL);
    printk(KERN_INFO "msm_i2c_probe: clk_ctl %x, %d Hz/n",
           clk_ctl, i2c_clk / (2 * ((clk_ctl & 0xff) + 3)));

    i2c_set_adapdata(&dev->adap_pri, dev); //dev(struct msm_i2c_dev)->adap_pri(struct i2c_adapter)->dev->p->driver_data = dev(struct msm_i2c_dev)
    dev->adap_pri.algo = &msm_i2c_algo; //这个比较重要,使用来进行低层i2c通信的函数接口结构体
    strlcpy(dev->adap_pri.name,
        "MSM I2C adapter-PRI",
        sizeof(dev->adap_pri.name));

    dev->adap_pri.nr = pdev->id; //platform_device的 id 就成了i2c_adapter的编号
    ret = i2c_add_numbered_adapter(&dev->adap_pri); //先不讲,后面再说
    if (ret) {
        dev_err(&pdev->dev, "Primary i2c_add_adapter failed/n");
        goto err_i2c_add_adapter_failed;
    }

    i2c_set_adapdata(&dev->adap_aux, dev);  //struct msm_i2c_dev 中有两个struct i2c_adapter,初始化另一个
    dev->adap_aux.algo = &msm_i2c_algo;
    strlcpy(dev->adap_aux.name,
        "MSM I2C adapter-AUX",
        sizeof(dev->adap_aux.name));

    dev->adap_aux.nr = pdev->id + 1; //adapter 的编号不一样
    ret = i2c_add_numbered_adapter(&dev->adap_aux);
    if (ret) {
        dev_err(&pdev->dev, "auxiliary i2c_add_adapter failed/n");
        i2c_del_adapter(&dev->adap_pri);
        goto err_i2c_add_adapter_failed;
    }
    ret = request_irq(dev->irq, msm_i2c_interrupt,    //注册中断   
            IRQF_TRIGGER_RISING, pdev->name, dev);
    if (ret) {
        dev_err(&pdev->dev, "request_irq failed/n");
        goto err_request_irq_failed;
    }
    dev->pm_qos_req = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY,     //不知道是干啥的?
                         PM_QOS_DEFAULT_VALUE);
    if (!dev->pm_qos_req) {
        dev_err(&pdev->dev, "pm_qos_add_request failed/n");
        goto err_pm_qos_add_request_failed;
    }

    disable_irq(dev->irq);//中断屏蔽
    dev->suspended = 0;
    mutex_init(&dev->mlock);
    dev->clk_state = 0;
    /* Config GPIOs for primary and secondary lines */  //为两条i2c总线配置gpio
    pdata->msm_i2c_config_gpio(dev->adap_pri.nr, 1);
    pdata->msm_i2c_config_gpio(dev->adap_aux.nr, 1);
    clk_disable(dev->clk); //不知道干啥的?
    setup_timer(&dev->pwr_timer, msm_i2c_pwr_timer, (unsigned long) dev);//不知道干啥的?

    return 0;
......
}
好了该讲讲i2c_add_numbered_adapter(&dev->adap_pri)这个神气的函数了:
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
    int    id;
    int    status;

    if (adap->nr & ~MAX_ID_MASK) //判断adapter是不是合法
        return -EINVAL;
......
//上面的函数都是浮云,关键是下面的函数
    if (status == 0)
        status = i2c_register_adapter(adap);
    return status;
}
static int i2c_register_adapter(struct i2c_adapter *adap)
{
    int res = 0, dummy;

    /* Can't register until after driver model init */
    if (unlikely(WARN_ON(!i2c_bus_type.p))) {
        res = -EAGAIN;
        goto out_list;
    }

    rt_mutex_init(&adap->bus_lock);
    INIT_LIST_HEAD(&adap->userspace_clients);

    /* Set default timeout to 1 second if not already set */
    if (adap->timeout == 0)
        adap->timeout = HZ;

    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
    adap->dev.bus = &i2c_bus_type; //总线类型是i2c_bus_type
    adap->dev.type = &i2c_adapter_type; //设备类型是i2c_adapter_type
    res = device_register(&adap->dev); //该函数的讲解在下面,看看都做了什么
    if (res)
        goto out_list;

    dev_dbg(&adap->dev, "adapter [%s] registered/n", adap->name);

#ifdef CONFIG_I2C_COMPAT
    res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
                       adap->dev.parent);
    if (res)
        dev_warn(&adap->dev,
             "Failed to create compatibility class link/n");
#endif

    /* create pre-declared device nodes */
    if (adap->nr < __i2c_first_dynamic_bus_num)
        i2c_scan_static_board_info(adap);//好了,遇到最关键的函数了,在下面讲解

    /* Notify drivers */
    mutex_lock(&core_lock);
    dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
                 __process_new_adapter);//在i2c_bus_type 上寻找i2c_driver,让i2c_driver和i2c_adapter 建立联系,可惜,此时还没有i2c_driver
    mutex_unlock(&core_lock);

    return 0;

out_list:
    mutex_lock(&core_lock);
    idr_remove(&i2c_adapter_idr, adap->nr);
    mutex_unlock(&core_lock);
    return res;
}
int device_register(struct device *dev)
{
   device_initialize(dev);
   return device_add(dev);
}
device_initialize不讲了,直接device_add
int device_add(struct device *dev)
{
    struct device *parent = NULL;
    struct class_interface *class_intf;
    int error = -EINVAL;

    dev = get_device(dev); //这是让其引用计数加1
    if (!dev)
        goto done;

    if (!dev->p) {
        error = device_private_init(dev);//初始化dev->p(struct device_private)
        if (error)
            goto done;
    }

    /*
     * for statically allocated devices, which should all be converted
     * some day, we need to initialize the name. We prevent reading back
     * the name, and force the use of dev_name()
     */
    if (dev->init_name) {
        dev_set_name(dev, "%s", dev->init_name);
        dev->init_name = NULL;
    }

    if (!dev_name(dev)) {
        error = -EINVAL;
        goto name_error;
    }

    pr_debug("device: '%s': %s/n", dev_name(dev), __func__);

    parent = get_device(dev->parent); //adapter的父设备节点应该是i2c controler 的那个platform_device设备
    setup_parent(dev, parent);

    /* use parent numa_node */
    if (parent)
        set_dev_node(dev, dev_to_node(parent));

    /* first, register with generic layer. */
    /* we require the name to be set before, and pass NULL */
    error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
    if (error)
        goto Error;

    /* notify platform of device entry */
    if (platform_notify)
        platform_notify(dev);

    error = device_create_file(dev, &uevent_attr);
    if (error)
        goto attrError;

    if (MAJOR(dev->devt)) {
        error = device_create_file(dev, &devt_attr);
        if (error)
            goto ueventattrError;

        error = device_create_sys_dev_entry(dev);
        if (error)
            goto devtattrError;

        devtmpfs_create_node(dev);
    }

    error = device_add_class_symlinks(dev);
    if (error)
        goto SymlinkError;
    error = device_add_attrs(dev);
    if (error)
        goto AttrsError;
    error = bus_add_device(dev);//i2c_bus_type 添加该adatper 设备
    if (error)
        goto BusError;
    error = dpm_sysfs_add(dev);
    if (error)
        goto DPMError;
    device_pm_add(dev);

    /* Notify clients of device addition.  This call must come
     * after dpm_sysf_add() and before kobject_uevent().
     */
    if (dev->bus)
        blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
                         BUS_NOTIFY_ADD_DEVICE, dev);

    kobject_uevent(&dev->kobj, KOBJ_ADD);
    bus_probe_device(dev); //这个函数的愿意是探测adapter设备的driver,但是adapter本就没有driver,所以该函数就无功而反了。
    if (parent)
        klist_add_tail(&dev->p->knode_parent,
                   &parent->p->klist_children);// adapter的父设备节点应该是i2c controler 的那个platform_device设备,这个函数很有用,待会儿遇到i2c_client时会很有用。

    if (dev->class) {
        mutex_lock(&dev->class->p->class_mutex);
        /* tie the class to the device */
        klist_add_tail(&dev->knode_class,
                   &dev->class->p->class_devices);

        /* notify any interfaces that the device is here */
        list_for_each_entry(class_intf,
                    &dev->class->p->class_interfaces, node)
            if (class_intf->add_dev)
                class_intf->add_dev(dev, class_intf);
        mutex_unlock(&dev->class->p->class_mutex);
    }
......
}
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
    struct i2c_devinfo    *devinfo;

    down_read(&__i2c_board_lock);
    list_for_each_entry(devinfo, &__i2c_board_list, list) {
        if (devinfo->busnum == adapter->nr
                && !i2c_new_device(adapter,
                        &devinfo->board_info))
            dev_err(&adapter->dev,
                "Can't create device at 0x%02x/n",
                devinfo->board_info.addr);
    }
    up_read(&__i2c_board_lock);
}
我们前面讲过,板子初始化时会把所有的i2c外围设备的信息结构struct i2c_board_info分装成struct i2c_devinfo结构,放到了__i2c_board_list链表中,是时候用了。先判断adapter的编号对不对,之后call i2c_new_device。
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
    struct i2c_client    *client;
    int            status;

    client = kzalloc(sizeof *client, GFP_KERNEL);
    if (!client)
        return NULL;

    client->adapter = adap;

    client->dev.platform_data = info->platform_data;

    if (info->archdata)
        client->dev.archdata = *info->archdata;

    client->flags = info->flags;
    client->addr = info->addr;
    client->irq = info->irq;

    strlcpy(client->name, info->type, sizeof(client->name));

    /* Check for address validity */
    status = i2c_check_client_addr_validity(client); //检查该地址的合法性
    if (status) {
        dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx/n",
            client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
        goto out_err_silent;
    }

    /* Check for address business */
    status = i2c_check_addr_busy(adap, client->addr);//你这个info->addr的地址,在我的adapter所支持的client的addr冲突了嘛,也就是i2c_adapter->device->device_private->klist(klist_children)链接了i2c_client->device->device_private->knod(knode_parent),但是此时adapter中还没有加载任何的client,那么是什么时候加载的呢,往下看
    if (status)
        goto out_err;

    client->dev.parent = &client->adapter->dev;//这一步也很关键,client->dev->parent设置成了adapter->dev
    client->dev.bus = &i2c_bus_type;
    client->dev.type = &i2c_client_type;//设备类型是i2c_client_type, adapter是i2c_adapter_type
#ifdef CONFIG_OF
    client->dev.of_node = info->of_node;
#endif

    dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
             client->addr);
    status = device_register(&client->dev);//好了,我们有碰见这个函数了,前面注册adapter的时候就用过他,好了就让我们看一看那最关键的几步吧。
......
}
int device_register(struct device *dev)
{
   device_initialize(dev);略过......
   return device_add(dev);
}
int device_add(struct device *dev)
{
......
    parent = get_device(dev->parent);
    setup_parent(dev, parent);

    /* use parent numa_node */
    if (parent)
        set_dev_node(dev, dev_to_node(parent));//前面的注释中有也句“这一步也很关键”,找找,对了,那么此处的parent就是adapter->dev
......
    error = bus_add_device(dev);//i2c_bus_type总线添加i2c_client这个设备
......
    bus_probe_device(dev);//i2c_client没有对应的driver,所以无功返回
    if (parent)
        klist_add_tail(&dev->p->knode_parent,
                   &parent->p->klist_children);//好啦,就是这一句,这关键的一句,真实众里寻他千百度,漠然回首......我们以前见过!真实命运的作弄阿,以前一直不知道他的重要性,就像小时候你身边熟悉却不懂的人--父亲,长大了才知道当初他的一片苦心,汗颜!解释这句话就是把client->p->knode_parent 链接到了adapter->p->klist_children的尾部。让adapter和他所支持的client建立了联系,当然一个adapter可能会支持好几个client,关键看struct i2c_devinfo下的busnum和该adapter的编号nr等不等。

......
}

以上就是板子启动中platform_device msm_i2c和i2c controler driver的有关部分,可能你还没有完全明白,那好吧,我们就做一个大白话的总结!
1、板子启动时注册作为平台设备的i2c controler设备,之后将所有的i2c 外围设备的资源信息以i2c_devinfo{i2c_board_info}的形式放到了一个全局链表中。
2、在i2c controler driver的加载过程中, 创建struct msm_i2c_dev结构体和platform_device msm_i2c 对应,struct msm_i2c_dev中有两个i2c_adapter成员,创建他们,并且从那个全局链表中找到该adapter所支持的i2c_client,创建他们,并且让i2c_adapter 和i2c_client建立关联,以备以后查找。
现在所有的准备工作都已经就绪,只等i2c设备的driver一加载,i2c的设备就能正常工作了!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值