IC2总线及驱动

发布时间 2023-04-05 23:19:56作者: 流水灯

I2C总线

I2C总线和 platform 总线非常类似,platform 总线初始化位置如下:

kernel_init();
    kernel_init_freeable();
        do_basic_setup();
            driver_init();
                platform_bus_init();

 

I2C总线是作为一个模块进行初始化

postcore_initcall(i2c_init);
 #define postcore_initcall(fn)       __define_initcall(fn, 2)

 

由此可见,platform 总线不可或缺,I2C总线是可以被裁剪的。

 

I2C总线的全局变量如下:

 

 

I2C适配器

每一个soc上基本都会有一个或者多个I2C控制器,每一个I2C控制器下面接的就是SCL 和 SDA 两条线。I2C设备设备都是挂在这两条线下面的,这就是就硬件层的基本结构。

硬件层的上面就是Linux内核中的适配器驱动层,每一个soc厂家都会在Linux框架上实现自家IIC控制的的驱动程序,这部分是由soc厂家的bsp工程师提供的。其实就是根据I2C控制器的寄存器操作实现了如何将数据送到I2C总线下的设备中去,以及怎么读取数据。厂家将这一层封装好,驱动工程师写驱动的时候就只需要根据具体的I2C设备来读写数据,不需要自己来实现I2C时序。简单点就说设备驱动只负责准备要发的数据,告诉适配器就可以了。至于怎么发就是厂家自己去实现了,毕竟只有他们才最熟悉自家的芯片。

 

I2C适配器就是根据设备树提供的I2C控制器信息配置芯片,如下i2c1

            i2c1: i2c@21a0000 {
                #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";
            };

 

&i2c1 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    status = "okay";

    magnetometer@e {
        compatible = "fsl,mag3110";
        reg = <0x0e>;
        vdd-supply = <&reg_peri_3v3>;
        vddio-supply = <&reg_peri_3v3>;
        position = <2>;
    };

    fxls8471@1e {
        compatible = "fsl,fxls8471";
        reg = <0x1e>;
        position = <0>;
        interrupt-parent = <&gpio5>;
        interrupts = <0 8>;
    };
};

 

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, },
    { .compatible = "fsl,imx7d-i2c", .data = &imx7d_i2c_hwdata, },
    { /* sentinel */ }
};

static struct platform_driver i2c_imx_driver = {
    .probe = i2c_imx_probe,
    .remove = i2c_imx_remove,
    .driver = {
        .name = DRIVER_NAME,
        .pm = &i2c_imx_pm_ops,
        .of_match_table = i2c_imx_dt_ids,
        .acpi_match_table = i2c_imx_acpi_ids,
    },
    .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);
 

 

i2c_adap_imx_init() 是芯片厂家提供的适配器驱动,设备和驱动匹配执行 i2c_imx_probe() ,内容有:

添加 i2c_adapter_type 类型设备到 I2C 总线 (bus_add_device)

添加 i2c_client_type 类型设备到 I2C 总线

 

至此,soc上的adapter就和client进行了一个一一对应的绑定,而且都注册进内核总线上了。有多少个硬件adapter就会在总线上注册多少个client。