添加虚拟的i2c设备适配器(add virtual i2c adapter)

应用场景:在i2c从设备下再挂i2c从设备的情况,并且它们之间有可能存在断开链接。

目前车载视频传输多使用gmsl,gmsl2,FDP3.0协议进行传输,它们之间通过串行器和解串器进行连接。

所以在加载近端IC驱动后,要检测是否和远端IC已经link上,如果没有link上,则等待link成功;

如果link成功,则进行远端设备IC驱动的加载。

如果从link状态切换到unlink状态,则要卸载远端驱动,待重新link成功后,再重新加载远端驱动程序。

 

这时候就需要以下驱动程序

 

添加虚拟的i2c设备适配器

设备树定义如下:

/{

Example:

    i2c1: i2c@400a0000 {
        /* ... master properties skipped ... */
        clock-frequency = <100000>;   

        

        pca9532: gpio@60 {
            compatible = "nxp,pca9532";
            gpio-controller;
            #gpio-cells = <2>;
            reg = <0x60>;
        };
    };
};


&i2c0 {
        ser@50 {
            compatible = "max96751";
            reg = <0x50>;

            i2c {
                des@52 {
                    compatible = "max96752";
                    reg = <0x52>;
                };
            };
        };
    };

 

 

i2c_set_adapdata

i2c_add_numbered_adapter

 

static u32 serdes_i2c_func(struct i2c_adapter *adap)
{
    return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
}

static struct i2c_adapter *__get_alias_adapter(struct i2c_adapter *adap)
{
    struct i2c_client *client = i2c_get_adapdata(adap);
    /* Same i2c adapter used for the master device should be
     * used for communicating with the remote device via alias
     */
    return client->adapter;
}

int serdes_master_xfer(struct i2c_adapter *adap,
            struct i2c_msg msgs[], int num)
{
    struct i2c_adapter *alias_adap = __get_alias_adapter(adap);

    return i2c_transfer(alias_adap, msgs, num);
}
EXPORT_SYMBOL_GPL(serdes_master_xfer);

int serdes_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        unsigned short flags, char read_write,
        u8 command, int size, union i2c_smbus_data *data)
{
    struct i2c_adapter *alias_adap = __get_alias_adapter(adap);

    return i2c_smbus_xfer(alias_adap, addr, flags, read_write,
            command, size, data);

}
EXPORT_SYMBOL_GPL(serdes_smbus_xfer);

static const struct i2c_algorithm serdes_default_i2c_algo = {
    .master_xfer    = serdes_master_xfer,
    .smbus_xfer    = serdes_smbus_xfer,
    .functionality    = serdes_i2c_func,
};

int serdes_register_i2c_adapter(struct serdes_device *sd,
                const struct i2c_algorithm *algo)
{
    struct i2c_adapter *adap = NULL;

    dev_dbg(&sd->client->dev, "registering i2c adapter");

    adap = devm_kzalloc(&sd->client->dev, sizeof(*adap), GFP_KERNEL);
    if (adap == NULL)
        return -ENOMEM;

    sd->adap = adap;
    adap->nr = -1;
    adap->owner = THIS_MODULE;
    adap->class = I2C_CLASS_HWMON;
    adap->dev.parent = &sd->client->dev;
    adap->dev.of_node = sd->i2c_node;//这里的i2c-node是ser下的i2c节点

    if (algo)
        adap->algo = algo;
    else
        adap->algo = &serdes_default_i2c_algo;

    strlcpy(adap->name, "serdes i2c adapter", sizeof(adap->name));
    i2c_set_adapdata(adap, sd->client);

    return i2c_add_numbered_adapter(adap);
}
EXPORT_SYMBOL_GPL(serdes_register_i2c_adapter);

int serdes_remove_i2c_adapter(struct serdes_device *sd)
{
    if (sd->adap)
        i2c_del_adapter(sd->adap);

    sd->adap = NULL;
    return 0;
}
EXPORT_SYMBOL_GPL(serdes_remove_i2c_adapter);

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章