//总得来说三个主要步骤 //(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 */ }
作者:h32dong809 发表于2013-1-29 22:26:59 原文链接
阅读:78 评论:0 查看评论