//總得來說三個主要步驟
//(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 */
}
i.mx536(cotex-a8核)的I2C驅動理解一(probe)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.