In the previous section, we learned that the I2C framework is divided into three parts: I2C core, I2C bus driver and I2C device driver. Among them, the I2C bus driver is the SOC I2C controller driver, which is generally implemented by SOC manufacturers. The I2C device driver is actually implemented by users according to their different devices.
Under the imx6ull platform, NXP has officially implemented the I2C bus driver. Let’s briefly analyze it below.
First, find the device node of the I2C controller in the device tree. Open the imx6ull.dtsi file, it has the following content:
1 i2c1: i2c@021a0000 {
2 #address-cells = <1>;
3 #size-cells = <0>;
4 compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
5 reg = <0x021a0000 0x4000>;
6 interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
7 clocks = <&clks IMX6UL_CLK_I2C1>;
8 status = "disabled";
9 };
According to the compatible attribute values "fsl,imx6ul-i2c" and "fsl,imx21-i2c" in the I2C1 device node, we can find the corresponding driver files in the kernel, and search for these two strings in the Linux kernel source code. Find the driver file as drivers/i2c/busses/i2c-imx.c, with the following contents:
244 static struct platform_device_id imx_i2c_devtype[] = {
245 {
246 .name = "imx1-i2c",
247 .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
248 }, {
249 .name = "imx21-i2c",
250 .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
251 }, {
252 /* sentinel */
253 }
254 };
255 MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
256
257 static const struct of_device_id i2c_imx_dt_ids[] = {
258 {
.compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
259 {
.compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
260 {
.compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
261 {
/* sentinel */ }
262 };
263 MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
......
1119 static struct platform_driver i2c_imx_driver = {
1120 .probe = i2c_imx_probe,
1121 .remove = i2c_imx_remove,
1122 .driver = {
1123 .name = DRIVER_NAME,
1124 .owner = THIS_MODULE,
1125 .of_match_table = i2c_imx_dt_ids,
1126 .pm = IMX_I2C_PM,
1127 },
1128 .id_table = imx_i2c_devtype,
1129 };
1130
1131 static int __init i2c_adap_imx_init(void)
1132 {
1133 return platform_driver_register(&i2c_imx_driver);
1134 }
1135 subsys_initcall(i2c_adap_imx_init);
1136
1137 static void __exit i2c_adap_imx_exit(void)
1138 {
1139 platform_driver_unregister(&i2c_imx_driver);
1140 }
1141 module_exit(i2c_adap_imx_exit);
It can be seen from the above code that the essence of the I2C bus driver is also a standard platform driver framework, so the I2C bus driver is implemented based on the platform framework, which is equivalent to encapsulating another layer.
In line 259, the compatible attribute value is "fsl,imx21-i2c". The compatible attribute value of the i2c1 node in the device tree matches this. Therefore, the i2c-imx.c file is the I2C adapter driver file of I.MX6U.
In line 1120, the i2c_imx_probe function will be executed when the device and the driver are successfully matched, and the i2c_imx_probe function will complete the initialization of the I2C adapter.
Part of the i2c_imx_probe function is as follows:
971 static int i2c_imx_probe(struct platform_device *pdev)
972 {
973 const struct of_device_id *of_id =
974 of_match_device(i2c_imx_dt_ids, &pdev->dev);
975 struct imx_i2c_struct *i2c_imx;
976 struct resource *res;
977 struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
978 void __iomem *base;
979 int irq, ret;
980 dma_addr_t phy_addr;
981
982 dev_dbg(&pdev->dev, "<%s>\n", __func__);
983
984 irq = platform_get_irq(pdev, 0);
......
990 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
991 base = devm_ioremap_resource(&pdev->dev, res);
992 if (IS_ERR(base))
993 return PTR_ERR(base);
994
995 phy_addr = (dma_addr_t)res->start;
996 i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL);
997 if (!i2c_imx)
998 return -ENOMEM;
999
1000 if (of_id)
1001 i2c_imx->hwdata = of_id->data;
1002 else
1003 i2c_imx->hwdata = (struct imx_i2c_hwdata *)
1004 platform_get_device_id(pdev)->driver_data;
1005
1006 /* Setup i2c_imx driver structure */
1007 strlcpy(i2c_imx->adapter.name, pdev->name,
sizeof(i2c_imx->adapter.name));
1008 i2c_imx->adapter.owner = THIS_MODULE;
1009 i2c_imx->adapter.algo = &i2c_imx_algo;
1010 i2c_imx->adapter.dev.parent = &pdev->dev;
1011 i2c_imx->adapter.nr = pdev->id;
1012 i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
1013 i2c_imx->base = base;
1014
1015 /* Get I2C clock */
1016 i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
......
1022 ret = clk_prepare_enable(i2c_imx->clk);
......
1027 /* Request IRQ */
1028 ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr,
1029 IRQF_NO_SUSPEND, pdev->name, i2c_imx);
......
1035 /* Init queue */
1036 init_waitqueue_head(&i2c_imx->queue);
1037
1038 /* Set up adapter data */
1039 i2c_set_adapdata(&i2c_imx->adapter, i2c_imx);
1040
1041 /* Set up clock divider */
1042 i2c_imx->bitrate = IMX_I2C_BIT_RATE;
1043 ret = of_property_read_u32(pdev->dev.of_node,
1044 "clock-frequency", &i2c_imx->bitrate);
1045 if (ret < 0 && pdata && pdata->bitrate)
1046 i2c_imx->bitrate = pdata->bitrate;
1047
1048 /* Set up chip registers to defaults */
1049 imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
1050 i2c_imx, IMX_I2C_I2CR);
1051 imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx,
IMX_I2C_I2SR);
1052
1053 /* Add I2C adapter */
1054 ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
1055 if (ret < 0) {
1056 dev_err(&pdev->dev, "registration failed\n");
1057 goto clk_disable;
1058 }
1059
1060 /* Set up platform driver data */
1061 platform_set_drvdata(pdev, i2c_imx);
1062 clk_disable_unprepare(i2c_imx->clk);
......
1070 /* Init DMA config if supported */
1071 i2c_imx_dma_request(i2c_imx, phy_addr);
1072
1073 return 0; /* Return OK */
1074
1075 clk_disable:
1076 clk_disable_unprepare(i2c_imx->clk);
1077 return ret;
1078 }
On line 984, call platform_get_irq function to get the interrupt number.
On lines 990~991, call the platform_get_resource function to obtain the physical base address of the I2C1 controller register from the device tree, which is 0X021A0000. After obtaining the register base address, use the devm_ioremap_resource function to perform memory mapping on it to obtain a virtual address that can be used in the Linux kernel.
In line 996, NXP uses the imx_i2c_struct structure to represent the I2C controller of the I.MX series SOC. Here, the devm_kzalloc function is used to apply for memory.
Lines 1008~1013, the imx_i2c_struct structure must have a member variable called adapter. The adapter is i2c_adapter, and i2c_adapter is initialized here. Line 1009 sets the algo member variable of i2c_adapter to i2c_imx_algo, which is to set i2c_algorithm.
Lines 1028~1029, register the I2C controller interrupt, the interrupt service function is i2c_imx_isr.
Lines 1042~1044, set the I2C frequency to IMX_I2C_BIT_RATE=100KHz by default. If the device tree node has the "clock-frequency" attribute set, the I2C frequency will use the clock-frequency attribute value.
Lines 1049~1051 set the I2CR and I2SR registers controlled by I2C1.
On line 1054, call the i2c_add_numbered_adapter function to register the i2c_adapter with the Linux kernel.
Line 1071, apply for DMA. It seems that the I2C adapter driver of I.MX uses DMA.
The main work of i2c_imx_probe function is the following two points:
① Initialize i2c_adapter, set i2c_algorithm to i2c_imx_algo, and finally register i2c_adapter with Linux kernel.
② Initialize the relevant registers of the I2C1 controller.
i2c_imx_algo contains the communication function master_xfer between the I2C1 adapter and the I2C device. The i2c_imx_algo structure is defined as follows:
966 static struct i2c_algorithm i2c_imx_algo = {
967 .master_xfer = i2c_imx_xfer,
968 .functionality = i2c_imx_func,
969 };
Let's take a look first. functionality, functionality is used to return what kind of communication protocol this I2C adapter supports, here functionality is the i2c_imx_func function, the content of the i2c_imx_func function is as follows:
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
Focus on the i2c_imx_xfer function, because it is through this function to complete the communication with the I2C device. Part of the content of this function is as follows:
888 static int i2c_imx_xfer(struct i2c_adapter *adapter,
889 struct i2c_msg *msgs, int num)
890 {
891 unsigned int i, temp;
892 int result;
893 bool is_lastmsg = false;
894 struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
895
896 dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
897
898 /* Start I2C transfer */
899 result = i2c_imx_start(i2c_imx);
900 if (result)
901 goto fail0;
902
903 /* read/write data */
904 for (i = 0; i < num; i++) {
905 if (i == num - 1)
906 is_lastmsg = true;
907
908 if (i) {
909 dev_dbg(&i2c_imx->adapter.dev,
910 "<%s> repeated start\n", __func__);
911 temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
912 temp |= I2CR_RSTA;
913 imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
914 result = i2c_imx_bus_busy(i2c_imx, 1);
915 if (result)
916 goto fail0;
917 }
918 dev_dbg(&i2c_imx->adapter.dev,
919 "<%s> transfer message: %d\n", __func__, i);
920 /* write/read data */
......
938 if (msgs[i].flags & I2C_M_RD)
939 result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg);
940 else {
941 if (i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD)
942 result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
943 else
944 result = i2c_imx_write(i2c_imx, &msgs[i]);
945 }
946 if (result)
947 goto fail0;
948 }
949
950 fail0:
951 /* Stop I2C transfer */
952 i2c_imx_stop(i2c_imx);
953
954 dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
955 (result < 0) ? "error" : "success msg",
956 (result < 0) ? result : num);
957 return (result < 0) ? result : num;
958 }
On line 899, call the i2c_imx_start function to start I2C communication.
In line 939, if you are reading data from an I2C device, call the i2c_imx_read function.
Lines 941~945, write data to the I2C device. If you want to use DMA, use the i2c_imx_dma_write function to complete the data writing. If you don't use DMA, use the i2c_imx_write function to finish writing data.
In line 952, call i2c_imx_stop function to stop I2C communication after I2C communication is completed.
The functions i2c_imx_start, i2c_imx_read, i2c_imx_write and i2c_imx_stop are the specific operation functions of the I2C register.