summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBryan Wu <pengw@nvidia.com>2013-10-15 18:25:30 -0700
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2014-04-04 21:59:13 +0200
commit1cc39f2be8591a0b1d827bc4a1b2a3caaf3d2b65 (patch)
treeb70ee19147b7010e5ceaeb95a1ea5632d2bfb46a
parent87a9c8114beba2fa8be6e74a182557f08965ddd6 (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.c87
1 files changed, 87 insertions, 0 deletions
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);