summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorBryan Wu <pengw@nvidia.com>2014-08-18 16:27:27 -0700
committerMatthew Pedro <mapedro@nvidia.com>2015-04-14 11:30:25 -0700
commitdf86d46c835f58e0537c8c2a8d258589963d5f17 (patch)
treeaf322a34f66669b33664391a55536066f0fe7f96 /drivers/media
parent62ac79266ebff845d01cf3296e54c64b49119129 (diff)
media: tegra_v4l2_camera: add CSI caliabration
Add calibration for T124 VI2. Bug 1628147 Change-Id: If70b1562c1d6345b337e4a01236c392b79f14dad Signed-off-by: Bryan Wu <pengw@nvidia.com> Reviewed-on: http://git-master/r/678605 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Frank Chen <frankc@nvidia.com> Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/common.c9
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/common.h6
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/vi2.c193
3 files changed, 205 insertions, 3 deletions
diff --git a/drivers/media/platform/soc_camera/tegra_camera/common.c b/drivers/media/platform/soc_camera/tegra_camera/common.c
index 4b08514c459f..3bbceced0ade 100644
--- a/drivers/media/platform/soc_camera/tegra_camera/common.c
+++ b/drivers/media/platform/soc_camera/tegra_camera/common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -217,6 +217,13 @@ static int tegra_camera_capture_frame(struct tegra_camera_dev *cam)
cam->ops->incr_syncpts(cam);
+ /* MIPI CSI pads calibration after starting capture */
+ if (cam->ops->mipi_calibration && !cam->cal_done) {
+ err = cam->ops->mipi_calibration(cam);
+ if (!err)
+ cam->cal_done = 1;
+ }
+
while (retry) {
err = cam->ops->capture_start(cam, buf);
/* Capturing succeed, stop capturing */
diff --git a/drivers/media/platform/soc_camera/tegra_camera/common.h b/drivers/media/platform/soc_camera/tegra_camera/common.h
index 084d45f03b98..d4ffe414d7d8 100644
--- a/drivers/media/platform/soc_camera/tegra_camera/common.h
+++ b/drivers/media/platform/soc_camera/tegra_camera/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -75,6 +75,8 @@ struct tegra_camera_ops {
void (*activate)(struct tegra_camera_dev *vi2_cam);
void (*deactivate)(struct tegra_camera_dev *vi2_cam);
int (*port_is_valid)(int port);
+
+ int (*mipi_calibration)(struct tegra_camera_dev *vi2_cam);
};
struct tegra_camera_dev {
@@ -120,6 +122,8 @@ struct tegra_camera_dev {
int tpg_mode;
int sof;
+
+ int cal_done;
};
#define TC_VI_REG_RD(dev, offset) readl(dev->reg_base + offset)
diff --git a/drivers/media/platform/soc_camera/tegra_camera/vi2.c b/drivers/media/platform/soc_camera/tegra_camera/vi2.c
index 134ab24b536e..3f3b8bfc7d9b 100644
--- a/drivers/media/platform/soc_camera/tegra_camera/vi2.c
+++ b/drivers/media/platform/soc_camera/tegra_camera/vi2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2014, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
+#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <media/soc_camera.h>
@@ -286,6 +287,52 @@
#define TEGRA_IMAGE_DT_RAW12 44
#define TEGRA_IMAGE_DT_RAW14 45
+#define MIPI_CAL_CTRL 0x00
+#define STARTCAL (1 << 0)
+#define CLKEN_OVR (1 << 4)
+#define MIPI_CAL_AUTOCAL_CTRL0 0x04
+#define CIL_MIPI_CAL_STATUS 0x08
+#define CAL_DONE (1 << 16)
+#define CIL_MIPI_CAL_STATUS_2 0x0c
+#define CILA_MIPI_CAL_CONFIG 0x14
+#define SELA (1 << 21)
+#define CILB_MIPI_CAL_CONFIG 0x18
+#define SELB (1 << 21)
+#define CILC_MIPI_CAL_CONFIG 0x1c
+#define SELC (1 << 21)
+#define CILD_MIPI_CAL_CONFIG 0x20
+#define SELD (1 << 21)
+#define CILE_MIPI_CAL_CONFIG 0x24
+#define SELE (1 << 21)
+#define DSIA_MIPI_CAL_CONFIG 0x38
+#define SELDSIA (1 << 21)
+#define DSIB_MIPI_CAL_CONFIG 0x3c
+#define SELDSIB (1 << 21)
+#define MIPI_BIAS_PAD_CFG0 0x58
+#define E_VCLAMP_REF (1 << 0)
+#define MIPI_BIAS_PAD_CFG1 0x5c
+#define MIPI_BIAS_PAD_CFG2 0x60
+#define PDVREG (1 << 1)
+#define DSIA_MIPI_CAL_CONFIG_2 0x64
+#define CLKSELDSIA (1 << 21)
+#define DSIB_MIPI_CAL_CONFIG_2 0x68
+#define CLKSELDSIB (1 << 21)
+#define CILC_MIPI_CAL_CONFIG_2 0x6c
+#define CLKSELC (1 << 21)
+#define CILD_MIPI_CAL_CONFIG_2 0x70
+#define CLKSELD (1 << 21)
+#define CSIE_MIPI_CAL_CONFIG_2 0x74
+#define CLKSELE (1 << 21)
+
+#define MIPI_CAL_BASE 0x700e3000
+
+static const struct regmap_config mipi_cal_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int vi2_port_is_valid(int port)
{
return (((port) >= TEGRA_CAMERA_PORT_CSI_A) &&
@@ -983,6 +1030,148 @@ static void vi2_sw_reset(struct tegra_camera_dev *cam)
udelay(10);
}
+
+
+static int vi2_mipi_calibration(struct tegra_camera_dev *cam)
+{
+ void __iomem *mipi_cal;
+ struct regmap *regs;
+ struct platform_device *pdev = cam->ndev;
+ struct vb2_buffer *vb = cam->active;
+ struct tegra_camera_buffer *buf = to_tegra_vb(vb);
+ struct soc_camera_device *icd = buf->icd;
+ struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+ struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+ int port = pdata->port;
+ u32 val;
+ struct clk *clk_mipi_cal = NULL, *clk_72mhz = NULL;
+ int retry = 500;
+
+ /* TPG mode doesn't need any calibration */
+ if (cam->tpg_mode)
+ return 0;
+
+ /* Get clks for MIPI Calibration */
+ clk_mipi_cal = clk_get_sys("mipi-cal", NULL);
+ if (IS_ERR_OR_NULL(clk_mipi_cal)) {
+ dev_err(&pdev->dev, "cannot get mipi-cal clk.\n");
+ return PTR_ERR(clk_mipi_cal);
+ }
+
+ clk_72mhz = clk_get_sys("clk72mhz", NULL);
+ if (IS_ERR_OR_NULL(clk_72mhz)) {
+ dev_err(&pdev->dev, "cannot get 72MHz clk.\n");
+ return PTR_ERR(clk_72mhz);
+ }
+
+ /* Map registers */
+ mipi_cal = ioremap(MIPI_CAL_BASE, 0x100);
+ if (!mipi_cal)
+ return -ENOMEM;
+
+ regs = devm_regmap_init_mmio(&pdev->dev, mipi_cal, &mipi_cal_config);
+ if (IS_ERR(regs)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ iounmap(mipi_cal);
+ return PTR_ERR(regs);
+ }
+
+ /* Enable MIPI Calibration clocks */
+ if (clk_mipi_cal)
+ clk_prepare_enable(clk_mipi_cal);
+ if (clk_72mhz)
+ clk_prepare_enable(clk_72mhz);
+
+ /* MIPI_CAL_CLKEN_OVR = 1 */
+ regmap_update_bits(regs, MIPI_CAL_CTRL, CLKEN_OVR, CLKEN_OVR);
+
+ /* Clear MIPI CAL status flags */
+ regmap_write(regs, CIL_MIPI_CAL_STATUS, 0xF1F10000);
+ regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG, SELDSIA, 0);
+ regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG, SELDSIB, 0);
+ regmap_update_bits(regs, MIPI_BIAS_PAD_CFG0,
+ E_VCLAMP_REF, E_VCLAMP_REF);
+ regmap_update_bits(regs, MIPI_BIAS_PAD_CFG2, PDVREG, 0);
+ regmap_update_bits(regs, CILA_MIPI_CAL_CONFIG, SELA, 0);
+ regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG_2, CLKSELDSIA, 0);
+ regmap_update_bits(regs, CILB_MIPI_CAL_CONFIG, SELB, 0);
+ regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG_2, CLKSELDSIB, 0);
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELC, 0);
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG_2, CLKSELC, 0);
+ regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG, SELD, 0);
+ regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG_2, CLKSELD, 0);
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELE, 0);
+ regmap_update_bits(regs, CSIE_MIPI_CAL_CONFIG_2, CLKSELE, 0);
+
+ /* Select the CIL pad for auto calibration */
+ switch (port) {
+ case TEGRA_CAMERA_PORT_CSI_A:
+ regmap_update_bits(regs, CILA_MIPI_CAL_CONFIG, SELA, SELA);
+ regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG_2, CLKSELDSIA, 0);
+ if (pdata->lanes > 2) {
+ regmap_update_bits(regs, CILB_MIPI_CAL_CONFIG,
+ SELB, SELB);
+ regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG_2,
+ CLKSELDSIB, 0);
+ }
+ break;
+ case TEGRA_CAMERA_PORT_CSI_B:
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELC, SELC);
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG_2, CLKSELC, 0);
+ if (pdata->lanes > 2) {
+ regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG,
+ SELD, SELD);
+ regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG_2,
+ CLKSELD, 0);
+ }
+ break;
+ case TEGRA_CAMERA_PORT_CSI_C:
+ regmap_update_bits(regs, CILE_MIPI_CAL_CONFIG, SELE, SELE);
+ regmap_update_bits(regs, CSIE_MIPI_CAL_CONFIG_2,
+ CLKSELE, CLKSELE);
+ break;
+ default:
+ dev_err(&pdev->dev, "wrong port %d\n", port);
+ }
+
+ /* Trigger calibration */
+ regmap_update_bits(regs, MIPI_CAL_CTRL, STARTCAL, STARTCAL);
+ while (--retry) {
+ regmap_read(regs, CIL_MIPI_CAL_STATUS, &val);
+ if (val & CAL_DONE)
+ break;
+ usleep_range(200, 300);
+ }
+
+ /* Cleanup: un-select to avoid interference with DSI */
+ regmap_update_bits(regs, CILA_MIPI_CAL_CONFIG, SELA, 0);
+ regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG_2,
+ CLKSELDSIA, CLKSELDSIA);
+ regmap_update_bits(regs, CILB_MIPI_CAL_CONFIG, SELB, 0);
+ regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG_2,
+ CLKSELDSIB, CLKSELDSIB);
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELC, 0);
+ regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG_2, CLKSELC, CLKSELC);
+ regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG, SELD, 0);
+ regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG_2, CLKSELD, CLKSELD);
+ regmap_update_bits(regs, CILE_MIPI_CAL_CONFIG, SELE, 0);
+ regmap_update_bits(regs, CSIE_MIPI_CAL_CONFIG_2, CLKSELE, 0);
+
+ /* Disable clocks */
+ if (clk_mipi_cal)
+ clk_disable_unprepare(clk_mipi_cal);
+ if (clk_72mhz)
+ clk_disable_unprepare(clk_72mhz);
+
+ if (!retry) {
+ dev_err(&pdev->dev, "MIPI calibration timeout!\n");
+ return -EBUSY;
+ }
+
+ dev_info(&pdev->dev, "MIPI calibration for CSI is done\n");
+ return 0;
+}
+
struct tegra_camera_ops vi2_ops = {
.clks_init = vi2_clks_init,
.clks_deinit = vi2_clks_deinit,
@@ -1001,6 +1190,8 @@ struct tegra_camera_ops vi2_ops = {
.incr_syncpts = vi2_incr_syncpts,
.port_is_valid = vi2_port_is_valid,
+
+ .mipi_calibration = vi2_mipi_calibration,
};
int vi2_register(struct tegra_camera_dev *cam)