打印
[资料分享与下载]

i.mx536(cotex-a8核)的I2C驱动理解一(probe)

[复制链接]
779|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ccw1986|  楼主 | 2015-7-3 10:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    //总得来说三个主要步骤  
    //(1)映射虚拟内存,注册中断等  
    //(2)填充结构体struct imx_i2c_struct  
    //(3)调用i2c_register_adapter注册I2C设备  
    static int __init i2c_imx_probe(struct platform_device *pdev)  
    {  
        //分析了几个驱动发现,平台驱动有很多相似的地方,比如说在prode里一般都会定义  
        //一个platform_data结构体,一个对应设备的结构体比如struct imx_i2c_struct  
        struct imx_i2c_struct *i2c_imx;  
        struct resource *res;  
        struct imxi2c_platform_data *pdata;  
        //__iomem表示指针是指向一个I/O的内存空间  
        void __iomem *base;  
        //resource_size_t = u32  
        resource_size_t res_size;  
        int irq;  
        int ret;  
      
        dev_dbg(&pdev->dev, "<%s>\n", __func__);  
        //获取IO资源和中断资源  
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
        if (!res) {  
            dev_err(&pdev->dev, "can't get device resources\n");  
            return -ENOENT;  
        }  
        //获取中断资源  
        irq = platform_get_irq(pdev, 0);  
        if (irq < 0) {  
            dev_err(&pdev->dev, "can't get irq number\n");  
            return -ENOENT;  
        }  
      
        pdata = pdev->dev.platform_data;  
      
        if (pdata && pdata->init) {  
            ret = pdata->init(&pdev->dev);  
            if (ret)  
                return ret;  
        }  
      
        res_size = resource_size(res);  
        //检测该IO资源是否可用,若可用,并标志为已用  
        if (!request_mem_region(res->start, res_size, DRIVER_NAME)) {  
            ret = -EBUSY;  
            goto fail0;  
        }  
        //映射物理地址到虚拟内存  
        base = ioremap(res->start, res_size);  
        if (!base) {  
            dev_err(&pdev->dev, "ioremap failed\n");  
            ret = -EIO;  
            goto fail1;  
        }  
        //给i2c_imx分配内存,并初始化为0  
        i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL);  
        if (!i2c_imx) {  
            dev_err(&pdev->dev, "can't allocate interface\n");  
            ret = -ENOMEM;  
            goto fail2;  
        }  
      
         
        //填充结构体i2c_imx  
        strcpy(i2c_imx->adapter.name, pdev->name);  
        //i2c_adapter,Linux的I2C驱动框架中的主要数据结构(i2c_driver、i2c_client、i2c_adapter和i2c_algorithm)之一出现了  
        //对应于物理上的一个适配器  
        i2c_imx->adapter.owner       = THIS_MODULE;  
        //i2c_algorithm也出现了  
        //i2c_algorithm主要提供通信的函数  
        i2c_imx->adapter.algo        = &i2c_imx_algo;  
        i2c_imx->adapter.dev.parent  = &pdev->dev;  
        i2c_imx->adapter.nr      = pdev->id;  
        i2c_imx->irq         = irq;  
        i2c_imx->base            = base;  
        i2c_imx->res         = res;  
      
        /* Get I2C clock */  
        //开启I2C时钟源  
        i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");  
        if (IS_ERR(i2c_imx->clk)) {  
            ret = PTR_ERR(i2c_imx->clk);  
            dev_err(&pdev->dev, "can't get I2C clock\n");  
            goto fail3;  
        }  
      
        /* Request IRQ */  
        //注册中断函数i2c_imx_isr  
        ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx);  
        if (ret) {  
            dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq);  
            goto fail4;  
        }  
      
        /* Init queue */  
        //初始化queue  
        init_waitqueue_head(&i2c_imx->queue);  
      
        /* Set up adapter data */  
        //把I2C_imx保存到adapter中,最终可以调用i2c_get_adapdata获取  
        i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);  
      
        /* Set up clock divider */  
        //这个pdata->bitrate在板级配置文件中设置  
        if (pdata && pdata->bitrate)  
            i2c_imx_set_clk(i2c_imx, pdata->bitrate);  
        else  
            i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE);  
      
        /* Set up chip registers to defaults */  
        writeb(0, i2c_imx->base + IMX_I2C_I2CR);  
        writeb(0, i2c_imx->base + IMX_I2C_I2SR);  
      
        /* Add I2C adapter */  
        //重要的函数来了,  
        //i2c_add_numbered_adapter最终调用i2c_register_adapter添加I2C控制器  
        ret = i2c_add_numbered_adapter(&i2c_imx->adapter);  
        if (ret < 0) {  
            dev_err(&pdev->dev, "registration failed\n");  
            goto fail5;  
        }  
      
        /* Set up platform driver data */  
        platform_set_drvdata(pdev, i2c_imx);  
        //打印调试信息  
        dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq);  
        dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n",  
            i2c_imx->res->start, i2c_imx->res->end);  
        dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n",  
            res_size, i2c_imx->res->start);  
        dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",  
            i2c_imx->adapter.name);  
        dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");  
      
        return 0;   /* Return OK */  
      
    fail5:  
        free_irq(i2c_imx->irq, i2c_imx);  
    fail4:  
        clk_put(i2c_imx->clk);  
    fail3:  
        kfree(i2c_imx);  
    fail2:  
        iounmap(base);  
    fail1:  
        release_mem_region(res->start, resource_size(res));  
    fail0:  
        if (pdata && pdata->exit)  
            pdata->exit(&pdev->dev);  
        return ret; /* Return error number */  
    }  


相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

925

帖子

6

粉丝