應用場景:在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);