我正在开发一款嵌入式板的驱动程序。该驱动程序应该为 v4l2 开放接口,并使用 i2c 与2个设备通信。驱动程序将充当主机。
我似乎无法理解 i2c_device_id
数组和 i2c_add_driver
函数的工作原理。我在内核源代码中阅读了文档,但对于多个从设备客户端无法帮助我。
- 我需要有两个单独的探测函数吗?
- 我需要两次调用
i2c_add_driver
吗? - 如果不是这样,我如何能够保存两个不同的客户端以便能够向不同的地址发送不同的字节。
我在此粘贴了我的代码。我尝试实例化两个 i2c_drivers
,两次调用 i2c_driver_add
,并分别实现了 i2c 探测。但代码不起作用,告诉我当第二次调用 i2c_add_driver
时,foo1
已经注册。
我在 dts 文件中定义了两个块在 i2c1
下面:
&i2c1 {
...
foo0: foo0@00 {
compatible = "bar,foo0";
reg = <0x00>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu1_2>;
clocks = <&clks IMX6QDL_CLK_CKO>;
clock-names = "csi_mclk";
DOVDD-supply = <&vgen4_reg>; /* 1.8v */
AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3,
on rev B board is VGEN5 */
DVDD-supply = <&vgen2_reg>; /* 1.5v*/
pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */
rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */
csi_id = <0>;
mclk = <24000000>;
mclk_source = <0>;
};
foo1: foo1@02 {
compatible = "bar, foo1";
reg = <0x02>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ipu1_2>;
clocks = <&clks IMX6QDL_CLK_CKO>;
clock-names = "csi_mclk";
DOVDD-supply = <&vgen4_reg>; /* 1.8v */
AVDD-supply = <&vgen3_reg>; /* 2.8v, on rev C board is VGEN3,
on rev B board is VGEN5 */
DVDD-supply = <&vgen2_reg>; /* 1.5v*/
pwn-gpios = <&gpio1 16 1>; /* active low: SD1_DAT0 */
rst-gpios = <&gpio1 17 0>; /* active high: SD1_DAT1 */
csi_id = <0>;
mclk = <24000000>;
mclk_source = <0>;
};
...
两个块除了名称以外完全相同。
在驱动文件中,我实例化了以下结构体:
static const struct i2c_device_id foo_id[] = {
{"foo0", 0},
{"foo1", 1},
{},
};
static struct i2c_driver foo0_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "foo0",
},
.probe = foo0_probe,
.remove = foo0_remove,
.id_table = foo_id,
};
static struct i2c_driver foo1_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "foo1",
},
.probe = foo1_probe,
.remove = foo1_remove,
.id_table = foo_id,
};
以下是我的init
和exit
函数:
MODULE_DEVICE_TABLE(i2c, foo_id);
static __init int foo_init(void)
{
u8 err;
err = i2c_add_driver(&foo0_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed i2c-slave0, error=%d\n",
__func__, err);
err = i2c_add_driver(&foo1_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed i2c-slave1, error=%d\n",
__func__, err);
return err;
}
static void __exit foo_clean(void)
{
if((&foo0_i2c_driver) != NULL && i2c0initialized)
{
i2c_del_driver(&foo0_i2c_driver);
i2c0initialized = 0;
}
if((&foo1_i2c_driver) != NULL && i2c1initialized)
{
i2c_del_driver(&foo1_i2c_driver);
i2c1initialized = 0;
}
}
module_init(foo_init);
module_exit(foo_clean);
以下是我的probe
函数。 我为两个从机都准备了副本。
static int foo_probe(struct i2c_client *client,
const struct i2c_device_id *device_id)
{
struct pinctrl *pinctrls;
struct device *dev = &client->dev;
int ret = 0;
pinctrls = devm_pinctrl_get_select_default(dev);
if(IS_ERR(pinctrls))
{
dev_err(dev, "pinctrl setup failed\n");
return PTR_ERR(pinctrls);
}
memset(&foo_data, 0, sizeof(foo_data));
foo_data.sensor_clk = devm_clk_get(dev, "csi_mclk");
if(IS_ERR(foo_data.sensor_clk))
{
dev_err(dev, "get mclk failed\n");
return PTR_ERR(foo_data.sensor_clk);
}
ret = of_property_read_u32(dev->of_node, "mclk", &(foo_data.mclk));
if(ret < 0)
{
dev_err(dev, "mclk frequency is invalid\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "mclk_source",
(u32 *)&(foo_data.mclk_source));
if(ret < 0)
{
dev_err(dev, "mclk source is invalid\n");
return ret;
}
ret = of_property_read_u32(dev->of_node, "csi_id", &(foo_data.csi));
if(ret < 0)
{
dev_err(dev, "csi_id invalid\n");
return ret;
}
clk_prepare_enable(foo_data.sensor_clk);
i2c_client0 = client;
/* custom data structures are set here */
foo_reset();
ret = foo_get_id();
if(ret < 0 /* || ret != foo_ID */)
{
clk_disable_unprepare(foo_data.sensor_clk);
pr_warning("foo is not found\n");
return -ENODEV;
}
clk_disable_unprepare(foo_data.sensor_clk);
foo_int_device.priv = &foo_data;
ret = v4l2_int_device_register(&foo_int_device);
pr_info("foo is found\n");
i2c0initialized = 1;
return ret;
}