本文主要是介绍I.MX6ULL的I2C控制器的驱动分析说明一,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一. 简介
Linux 内核也将 I2C 驱动分为两部分:
(1) I2C 总线驱动, I2C 总线驱动就是 SOC 的 I2C 控制器驱动,也叫做 I2C 适配器驱动。
(2) I2C 设备驱动, I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动。
前面几篇文章学习了I2C驱动框架。
本文来简单分析一下 IMX6ULL的IMX6ULL的I2C控制器的驱动。
二. I.MX6ULL的I2C控制器的驱动分析
1. 查找 IMX6ULL的I2C控制器的驱动
i2c1: i2c@021a0000 {#address-cells = <1>;#size-cells = <0>;compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";reg = <0x021a0000 0x4000>;interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_I2C1>;status = "disabled";};
static struct platform_device_id imx_i2c_devtype[] = {{.name = "imx1-i2c",.driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,}, {.name = "imx21-i2c",.driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,}, {/* sentinel */}
};
MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);static const struct of_device_id i2c_imx_dt_ids[] = {{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
........................
static struct platform_driver i2c_imx_driver = {.probe = i2c_imx_probe,.remove = i2c_imx_remove,.driver = {.name = DRIVER_NAME,.owner = THIS_MODULE,.of_match_table = i2c_imx_dt_ids,.pm = IMX_I2C_PM,},.id_table = imx_i2c_devtype,
};static int __init i2c_adap_imx_init(void)
{return platform_driver_register(&i2c_imx_driver);
}
subsys_initcall(i2c_adap_imx_init);static void __exit i2c_adap_imx_exit(void)
{platform_driver_unregister(&i2c_imx_driver);
}
module_exit(i2c_adap_imx_exit);
2. i2c_imx_probe 函数
static int i2c_imx_probe(struct platform_device *pdev)
{const struct of_device_id *of_id = of_match_device(i2c_imx_dt_ids,&pdev->dev);struct imx_i2c_struct *i2c_imx;struct resource *res;struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);void __iomem *base;int irq, ret;dma_addr_t phy_addr;dev_dbg(&pdev->dev, "<%s>\n", __func__);irq = platform_get_irq(pdev, 0);
..........................res = platform_get_resource(pdev, IORESOURCE_MEM, 0);base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(base))return PTR_ERR(base);phy_addr = (dma_addr_t)res->start;i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);if (!i2c_imx)return -ENOMEM;if (of_id)i2c_imx->hwdata = of_id->data;elsei2c_imx->hwdata = (struct imx_i2c_hwdata *)platform_get_device_id(pdev)->driver_data;/* Setup i2c_imx driver structure */strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));i2c_imx->adapter.owner = THIS_MODULE;i2c_imx->adapter.algo = &i2c_imx_algo;i2c_imx->adapter.dev.parent = &pdev->dev;i2c_imx->adapter.nr = pdev->id;i2c_imx->adapter.dev.of_node = pdev->dev.of_node;i2c_imx->base = base;/* Get I2C clock */i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
.....................ret = clk_prepare_enable(i2c_imx->clk);
...................../* Request IRQ */ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr,IRQF_NO_SUSPEND, pdev->name, i2c_imx);
...................../* Init queue */init_waitqueue_head(&i2c_imx->queue);/* Set up adapter data */i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);/* Set up clock divider */i2c_imx->bitrate = IMX_I2C_BIT_RATE;ret = of_property_read_u32(pdev->dev.of_node,"clock-frequency", &i2c_imx->bitrate);if (ret < 0 && pdata && pdata->bitrate)i2c_imx->bitrate = pdata->bitrate;/* Set up chip registers to defaults */imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,i2c_imx, IMX_I2C_I2CR);imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);/* Add I2C adapter */ret = i2c_add_numbered_adapter(&i2c_imx->adapter);if (ret < 0) {dev_err(&pdev->dev, "registration failed\n");goto clk_disable;}/* Set up platform driver data */platform_set_drvdata(pdev, i2c_imx);clk_disable_unprepare(i2c_imx->clk);......................../* Init DMA config if supported */i2c_imx_dma_request(i2c_imx, phy_addr);return 0; /* Return OK */clk_disable:clk_disable_unprepare(i2c_imx->clk);return ret;
}
static struct i2c_algorithm i2c_imx_algo = {.master_xfer = i2c_imx_xfer,.functionality = i2c_imx_func,
};
接下来重点看一下 i2c_imx_xfer 函数的实现。
这篇关于I.MX6ULL的I2C控制器的驱动分析说明一的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!