From 7b863e3e0970fbe03d57f291bdc4aec9b60d3601 Mon Sep 17 00:00:00 2001 From: Junghyun Kim Date: Thu, 17 Apr 2025 08:34:14 +0000 Subject: [PATCH] kernel: cdi: Update fsync logic CIM version 3 for Ferrix is added in DT which can be used to select GPIO port number of IO expander to control the multiplexer for each deserializer Bug 5163582 Change-Id: I3ce608be9f5c18af005e1bc6fea9c73daeef7995 Signed-off-by: Junghyun Kim Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3342728 Reviewed-by: svcacv Reviewed-by: Mohit Ingale Reviewed-by: Frank Chen Reviewed-by: Chinmay Mahajan GVS: buildbot_gerritrpt --- .../media/platform/tegra/cdi/cdi-tca-priv.h | 1 - drivers/media/platform/tegra/cdi/cdi_dev.c | 58 ++++++++++++------- drivers/media/platform/tegra/cdi/cdi_mgr.c | 58 ++++++++++++++----- 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/drivers/media/platform/tegra/cdi/cdi-tca-priv.h b/drivers/media/platform/tegra/cdi/cdi-tca-priv.h index 10145018..6ee76474 100644 --- a/drivers/media/platform/tegra/cdi/cdi-tca-priv.h +++ b/drivers/media/platform/tegra/cdi/cdi-tca-priv.h @@ -27,7 +27,6 @@ struct tca9539_priv { u32 dat_len; u8 init_val[12]; u32 power_port; - u32 fsync_ctrl_port; bool enable; }; diff --git a/drivers/media/platform/tegra/cdi/cdi_dev.c b/drivers/media/platform/tegra/cdi/cdi_dev.c index bf00a1ac..da180365 100644 --- a/drivers/media/platform/tegra/cdi/cdi_dev.c +++ b/drivers/media/platform/tegra/cdi/cdi_dev.c @@ -436,7 +436,6 @@ static int cdi_dev_set_fsync_mux( void __user *arg) { u8 val, shift; - u8 cam_grp; struct cdi_dev_fsync_mux fsync_mux; if (copy_from_user(&fsync_mux, arg, sizeof(fsync_mux))) { @@ -451,14 +450,9 @@ static int cdi_dev_set_fsync_mux( * P05:P04 for the camera group D. cam_grp 3. */ if ((fsync_mux.cam_grp > 0U) && (fsync_mux.cam_grp < 4U)) { - if (info->tca9539.fsync_ctrl_port != -1) - cam_grp = info->tca9539.fsync_ctrl_port; - else - cam_grp = fsync_mux.cam_grp; - if (tca9539_rd(info, 0x02, &val) != 0) return -EFAULT; - switch (cam_grp) { + switch (fsync_mux.cam_grp) { case 1U: shift = 0U; break; @@ -473,6 +467,34 @@ static int cdi_dev_set_fsync_mux( break; } + val &= ~(0x3 << shift); + val |= (fsync_mux.mux_sel << shift); + if (tca9539_wr(info, 0x02, val) != 0) + return -EFAULT; + } + } else if (info->cim_ver == 3U) { + /* P01:P00 for the camera group A. cam_grp 1. + * P03:P02 for the camera group B. cam_grp 3. + * P05:P04 for the camera group D. cam_grp 2. + */ + if ((fsync_mux.cam_grp > 0U) && (fsync_mux.cam_grp < 4U)) { + if (tca9539_rd(info, 0x02, &val) != 0) + return -EFAULT; + switch (fsync_mux.cam_grp) { + case 1U: + shift = 0U; + break; + case 2U: + shift = 4U; + break; + case 3U: + shift = 2U; + break; + default: + shift = 0U; + break; + } + val &= ~(0x3 << shift); val |= (fsync_mux.mux_sel << shift); if (tca9539_wr(info, 0x02, val) != 0) @@ -567,10 +589,16 @@ static void cdi_dev_get_cim_ver(struct device_node *np, struct cdi_dev_info *inf dev_info(info->dev, "CIM A01\n"); info->cim_ver = 1U; - } else { + } else if (!strncmp(cim_ver, + "cim_ver_a02", + sizeof("cim_ver_a02"))) { dev_info(info->dev, "CIM A02\n"); info->cim_ver = 2U; + } else { + dev_info(info->dev, + "CIM A03\n"); + info->cim_ver = 3U; } } } @@ -592,7 +620,6 @@ static int cdi_dev_probe(struct i2c_client *client, int err; int numLinks = 0; int i; - u32 fsync_ctrl_port; dev_dbg(&client->dev, "%s: initializing link @%x-%04x\n", __func__, client->adapter->nr, client->addr); @@ -690,7 +717,7 @@ static int cdi_dev_probe(struct i2c_client *client, } } - if (info->cim_ver == 2U) { + if ((info->cim_ver == 2U) || (info->cim_ver == 3U)) { /* get the I/O expander information */ child_tca9539 = of_get_child_by_name(child, "tca9539"); if (child_tca9539 != NULL) { @@ -739,17 +766,6 @@ static int cdi_dev_probe(struct i2c_client *client, info->tca9539.power_port); return -ENODEV; } - info->tca9539.fsync_ctrl_port = -1; - err = of_property_read_u32(child_tca9539, - "fsync_ctrl_port", - &fsync_ctrl_port); - if (err == 0) { - if ((fsync_ctrl_port >= 0) && - (fsync_ctrl_port <= 3)) { - info->tca9539.fsync_ctrl_port = - fsync_ctrl_port; - } - } info->tca9539.reg_len /= 8; info->tca9539.dat_len /= 8; info->tca9539.enable = 1; diff --git a/drivers/media/platform/tegra/cdi/cdi_mgr.c b/drivers/media/platform/tegra/cdi/cdi_mgr.c index 01608aad..dec7e12a 100644 --- a/drivers/media/platform/tegra/cdi/cdi_mgr.c +++ b/drivers/media/platform/tegra/cdi/cdi_mgr.c @@ -1732,9 +1732,17 @@ static void cdi_mgr_get_cim_ver(struct device *dev, struct cdi_mgr_priv *cdi_mgr "CIM A01\n"); cdi_mgr->cim_ver = 1U; } else { - dev_info(dev, - "CIM A02\n"); - cdi_mgr->cim_ver = 2U; + if (!strncmp(cim_ver, + "cim_ver_a02", + sizeof("cim_ver_a02"))) { + dev_info(dev, + "CIM A02\n"); + cdi_mgr->cim_ver = 2U; + } else { + dev_info(dev, + "CIM A03\n"); + cdi_mgr->cim_ver = 3U; + } if (of_property_read_u32_array(cim, "cim_frsync_src", cdi_mgr->cim_frsync, @@ -1760,7 +1768,6 @@ static int cdi_mgr_probe(struct platform_device *pdev) struct device_node *child_tca9539 = NULL; struct device_node *root_node = NULL; const char *model; - u32 fsync_ctrl_port; dev_info(&pdev->dev, "%sing...\n", __func__); @@ -1993,17 +2000,6 @@ static int cdi_mgr_probe(struct platform_device *pdev) cdi_mgr->tca9539.power_port); goto err_probe; } - cdi_mgr->tca9539.fsync_ctrl_port = -1; - err = of_property_read_u32(child_tca9539, - "fsync_ctrl_port", - &fsync_ctrl_port); - if (err == 0) { - if ((fsync_ctrl_port >= 0) && - (fsync_ctrl_port <= 3)) { - cdi_mgr->tca9539.fsync_ctrl_port = - fsync_ctrl_port; - } - } cdi_mgr->tca9539.reg_len /= 8; cdi_mgr->tca9539.dat_len /= 8; @@ -2085,6 +2081,38 @@ static int cdi_mgr_probe(struct platform_device *pdev) __func__, err); goto err_probe; } + } else if (cdi_mgr->cim_ver == 3U) { /* P3966 */ + err = tca9539_wr(cdi_mgr, 0x6, 0xC0); + if (err != 0) { + dev_err(&pdev->dev, + "%s: ERR %d: TCA9539: Failed to select FS selection signal source\n", + __func__, err); + goto err_probe; + } + err = tca9539_wr(cdi_mgr, 0x7, 0x70); + if (err != 0) { + dev_err(&pdev->dev, + "%s: ERR %d: TCA9539: Failed to select PWDN signal source\n", + __func__, err); + goto err_probe; + } + + /* Configure FRSYNC logic */ + dev_info(&pdev->dev, + "FRSYNC source: %d %d %d\n", + cdi_mgr->cim_frsync[0], + cdi_mgr->cim_frsync[1], + cdi_mgr->cim_frsync[2]); + err = tca9539_wr(cdi_mgr, 0x2, + (cdi_mgr->cim_frsync[2] << 4) | + (cdi_mgr->cim_frsync[1] << 2) | + (cdi_mgr->cim_frsync[0])); + if (err < 0) { + dev_err(&pdev->dev, + "%s: ERR %d: TCA9539: Failed to set FRSYNC control logic\n", + __func__, err); + goto err_probe; + } } } }