- //总得来说三个主要步骤
- //(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 */
- }