From 1cc39f2be8591a0b1d827bc4a1b2a3caaf3d2b65 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Tue, 15 Oct 2013 18:25:30 -0700 Subject: media: tegra_v4l2: add CSI pad calibration Bug 1369083 Change-Id: I1a81bcb62e8f6bb654ffbebba09661187ab4b512 Signed-off-by: Bryan Wu Reviewed-on: http://git-master/r/309536 Tested-by: Vikram Fugro Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Kaustubh Purandare Reviewed-by: Winnie Hsu Reviewed-by: Matthew Pedro --- drivers/media/video/tegra_v4l2_camera.c | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c index 1e74aea88cfa..27b966a424f9 100644 --- a/drivers/media/video/tegra_v4l2_camera.c +++ b/drivers/media/video/tegra_v4l2_camera.c @@ -246,6 +246,7 @@ MODULE_PARM_DESC(internal_sync, "enable internal vsync and hsync decoded " \ #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 IS_INTERLACED ((pcdev->field == V4L2_FIELD_INTERLACED)\ || (pcdev->field == V4L2_FIELD_INTERLACED_BT)\ @@ -325,6 +326,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[] = { @@ -1116,6 +1120,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) @@ -1202,6 +1208,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 = @@ -1225,6 +1308,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); -- cgit v1.2.3