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