应用场景:在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);