在图显系统中,各显示IP(MIPI、HDMI、DP等)或屏幕的寄存器配置,可以通过I2C总线来实现。
以HDMI PHY芯片为例,分析在HDMI驱动中如何调用I2C接口实现HDMI PHY芯片寄存器的访问。
在slave设备的设备树结点中定义需要使用的I2C控制器。
hdmi: hdmi@12D00000 {
compatible = "samsung,exynos4210-hdmi";
...
phy = <&hdmi_i2c_phy>;
...
};
而hdmi_i2c_phy
从属于i2c_8。
i2c_8: i2c@138E0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-hdmiphy-i2c";
...
hdmi_i2c_phy: hdmiphy@38 {
compatible = "exynos4210-hdmiphy";
reg = <0x38>;
};
};
上面的hdmi_i2c_phy相当于是i2c_8的label索引,通过查看dtb的反汇编文件之后可以确定这一点。
i2c@138E0000 {
...
compatible = "samsung,s3c2440-hdmiphy-i2c";
...
hdmiphy@38 {
compatible = "exynos4210-hdmiphy";
reg = <0x38>;
linux,phandle = <0x43>;
phandle = <0x43>;
};
};
hdmi@12D00000 {
compatible = "samsung,exynos4212-hdmi";
...
phy = <0x43>;
...
};
在驱动代码中,我们需要做的事情是在HDMI驱动中通过解析设备树找到对应的I2C驱动,从而挂载相关的I2C数据传输接口函数。在下面的函数中主要涉及了3个API,分别是:of_find_compatible_node()
of_parse_phandle()
of_find_i2c_device_by_node
static int hdmi_get_phy_io(struct hdmi_context *hdata)
{
const char *compatible_str = "samsung,exynos4212-hdmiphy";
struct device_node *np;
int ret = 0;
np = of_find_compatible_node(NULL, NULL, compatible_str);
if (!np) {
np = of_parse_phandle(hdata->dev->of_node, "phy", 0);
if (!np) {
DRM_ERROR("Failed to find hdmiphy node in device tree\n");
return -ENODEV;
}
}
if (hdata->drv_data->is_apb_phy) {
hdata->regs_hdmiphy = of_iomap(np, 0);
if (!hdata->regs_hdmiphy) {
DRM_ERROR("failed to ioremap hdmi phy\n");
ret = -ENOMEM;
goto out;
}
} else {
hdata->hdmiphy_port = of_find_i2c_device_by_node(np);
if (!hdata->hdmiphy_port) {
DRM_INFO("Failed to get hdmi phy i2c client\n");
ret = -EPROBE_DEFER;
goto out;
}
}
out:
of_node_put(np);
return ret;
}
在通过i2c读写寄存器的时候,主要是通过调用i2c_master_send()
这个函数来实现的。
static int hdmiphy_reg_write_buf(struct hdmi_context *hdata,
u32 reg_offset, const u8 *buf, u32 len)
{
if ((reg_offset + len) > 32)
return -EINVAL;
if (hdata->hdmiphy_port) {
int ret;
ret = i2c_master_send(hdata->hdmiphy_port, buf, len);
if (ret == len)
return 0;
return ret;
} else {
int i;
for (i = 0; i < len; i++)
writel(buf[i], hdata->regs_hdmiphy +
((reg_offset + i)<<2));
return 0;
}
}
end
一口Linux
关注,回复【1024】海量Linux资料赠送
精彩文章合集
文章推荐
点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看