diff options
author | Bryan Wu <pengw@nvidia.com> | 2013-10-15 18:25:30 -0700 |
---|---|---|
committer | Matthew Pedro <mapedro@nvidia.com> | 2013-11-18 14:16:44 -0800 |
commit | 3c3f3589ca261a1e8d5e9355d540585fe1a164dd (patch) | |
tree | 4e8515118dce7b571f53c7a2ff5af9e3b0b09dd7 | |
parent | 2fb9cd0d92979598e3aa5319babdbe6be4c6df22 (diff) |
media: tegra_v4l2: add CSI pad calibration
Bug 1369083
Change-Id: I1a81bcb62e8f6bb654ffbebba09661187ab4b512
Signed-off-by: Bryan Wu <pengw@nvidia.com>
Reviewed-on: http://git-master/r/309536
Tested-by: Vikram Fugro <vfugro@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Kaustubh Purandare <kpurandare@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
-rw-r--r-- | drivers/media/video/tegra_v4l2_camera.c | 89 |
1 files changed, 88 insertions, 1 deletions
diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c index c96dae1389ff..8f71d1702537 100644 --- a/drivers/media/video/tegra_v4l2_camera.c +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -235,6 +235,7 @@ #define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x08c8 #define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x08cc #define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x08d0 +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x08d4 #define TC_VI_REG_RD(DEV, REG) readl(DEV->vi_base + REG) #define TC_VI_REG_WT(DEV, REG, VAL) writel(VAL, DEV->vi_base + REG) @@ -303,6 +304,9 @@ struct tegra_camera_dev { /* Debug */ int num_frames; int enable_refcnt; + + /* CSI pad calibration flag */ + int cal_done; }; static const struct soc_mbus_pixelfmt tegra_camera_formats[] = { @@ -974,7 +978,7 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port) static void tegra_camera_activate(struct tegra_camera_dev *pcdev) { - nvhost_module_busy_ext(pcdev->ndev); + nvhost_module_busy_ext(pcdev->ndev); /* Enable external power */ regulator_enable(pcdev->reg); @@ -1017,6 +1021,8 @@ static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev) regulator_disable(pcdev->reg); nvhost_module_idle_ext(pcdev->ndev); + + pcdev->cal_done = 0; } static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev) @@ -1104,6 +1110,83 @@ static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev) return err; } +static int tegra_camera_csi_pad_calibration(struct tegra_camera_dev *pcdev) +{ + struct vb2_buffer *vb = pcdev->active; + struct tegra_buffer *buf = to_tegra_vb(vb); + struct soc_camera_device *icd = buf->icd; + struct tegra_camera_platform_data *pdata = icd->link->priv; + int port = pdata->port; + int retry = 500; + u32 data; + int err = -EINVAL; + + TC_VI_REG_WT(pcdev, TEGRA_CSI_DSI_MIPI_CAL_CONFIG, 0x40300); + TC_VI_REG_WT(pcdev, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0, 0x50700); + + if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4) + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x200004); + + data = 0x2a000004; + if (port == TEGRA_CAMERA_PORT_CSI_A) + data |= 0x200000; /* MIPI_CAL_SELA */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data); + + /* Start calibration */ + data |= 0x80000000; + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data); + + while (retry--) { + data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); + if ((data & 0x8000) == 0x8000) + break; + udelay(20); + } + if (!retry) { + dev_warn(&pcdev->ndev->dev, "MIPI calibration timeout!\n"); + goto cal_out; + } + + /* Clear status */ + TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data); + retry = 500; + while (retry--) { + data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); + if ((data & 0x8000) == 0x0) + break; + udelay(20); + } + + if (!retry) { + dev_warn(&pcdev->ndev->dev, + "Clear MIPI calibration status timeout!\n"); + goto cal_out; + } + + data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); + err = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS); + if (data | err) { + dev_warn(&pcdev->ndev->dev, + "Calibration status not be cleared!\n"); + err = -EINVAL; + goto cal_out; + } + + /* Calibration succeed */ + err = 0; + +cal_out: + TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data); + + /* un-select to avoid interference with DSI */ + if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4) + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x4); + + TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x2a000004); + + return err; +} + static void tegra_camera_work(struct work_struct *work) { struct tegra_camera_dev *pcdev = @@ -1127,6 +1210,10 @@ static void tegra_camera_work(struct work_struct *work) spin_unlock_irq(&pcdev->videobuf_queue_lock); tegra_camera_capture_setup(pcdev); + if (!pcdev->cal_done) { + tegra_camera_csi_pad_calibration(pcdev); + pcdev->cal_done = 1; + } tegra_camera_capture_frame(pcdev); mutex_unlock(&pcdev->work_mutex); |