添加虛擬的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);

 

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