media: video: tegra: camera: move tegra_camera
Jihoon Bang [Thu, 27 Dec 2012 18:31:01 +0000 (10:31 -0800)]
Move tegra_camera from platform_driver to
part of nvhost vi driver. Split tegra_camera.c file into
multiple files incluidng camera.c, camera_power.c,
camera_emc.c and camera_clk.c according to functionality.

tegra_camera is registered/unregistered in nvhost vi driver.

Bug 1189789

Reviewed-on: http://git-master/r/174508
(cherry picked from commit e503a08b809844b53b7737e504e9f376f4a8a1eb)

Change-Id: Ia8e189e809e18e16b780d3ff064bc96db84ade85
Signed-off-by: Jihoon Bang <jbang@nvidia.com>
Reviewed-on: http://git-master/r/194805
Reviewed-by: Mandar Padmawar <mpadmawar@nvidia.com>
Tested-by: Mandar Padmawar <mpadmawar@nvidia.com>

23 files changed:
arch/arm/mach-tegra/board-dalmore-power.c
arch/arm/mach-tegra/board-dalmore.c
arch/arm/mach-tegra/board-pluto-power.c
arch/arm/mach-tegra/board-pluto.c
arch/arm/mach-tegra/tegra11_clocks.c
drivers/media/video/tegra/Kconfig
drivers/media/video/tegra/Makefile
drivers/media/video/tegra/ov5650.c
drivers/video/tegra/Kconfig
drivers/video/tegra/Makefile
drivers/video/tegra/camera/Makefile [new file with mode: 0644]
drivers/video/tegra/camera/camera.c [new file with mode: 0644]
drivers/video/tegra/camera/camera_clk.c [new file with mode: 0644]
drivers/video/tegra/camera/camera_clk.h [new file with mode: 0644]
drivers/video/tegra/camera/camera_emc.c [new file with mode: 0644]
drivers/video/tegra/camera/camera_emc.h [new file with mode: 0644]
drivers/video/tegra/camera/camera_power.c [new file with mode: 0644]
drivers/video/tegra/camera/camera_power.h [new file with mode: 0644]
drivers/video/tegra/camera/camera_priv_defs.h [new file with mode: 0644]
drivers/video/tegra/host/vi/Makefile
drivers/video/tegra/host/vi/vi.c
drivers/video/tegra/host/vi/vi.h [new file with mode: 0644]
include/video/tegra_camera.h [moved from include/media/tegra_camera.h with 100% similarity]

index 98ad38a..47c4521 100644 (file)
@@ -206,7 +206,7 @@ static struct regulator_consumer_supply max77663_sd2_supply[] = {
        REGULATOR_SUPPLY("avdd_usb_pll", "tegra-udc.0"),
        REGULATOR_SUPPLY("avdd_usb_pll", "tegra-ehci.0"),
        REGULATOR_SUPPLY("avdd_usb_pll", "tegra-ehci.1"),
-       REGULATOR_SUPPLY("vddio_cam", "tegra_camera"),
+       REGULATOR_SUPPLY("vddio_cam", "vi"),
        REGULATOR_SUPPLY("pwrdet_cam", NULL),
        REGULATOR_SUPPLY("avdd_osc", NULL),
        REGULATOR_SUPPLY("vddio_sys", NULL),
@@ -254,7 +254,7 @@ static struct regulator_consumer_supply max77663_ldo0_supply[] = {
        REGULATOR_SUPPLY("avdd_pllu", NULL),
        REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegradc.0"),
        REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegradc.1"),
-       REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegra_camera"),
+       REGULATOR_SUPPLY("avdd_csi_dsi_pll", "vi"),
 };
 
 static struct regulator_consumer_supply max77663_ldo1_supply[] = {
@@ -281,7 +281,7 @@ static struct regulator_consumer_supply max77663_ldo4_supply[] = {
 static struct regulator_consumer_supply max77663_ldo5_supply[] = {
        REGULATOR_SUPPLY("avdd_dsi_csi", "tegradc.0"),
        REGULATOR_SUPPLY("avdd_dsi_csi", "tegradc.1"),
-       REGULATOR_SUPPLY("avdd_dsi_csi", "tegra_camera"),
+       REGULATOR_SUPPLY("avdd_dsi_csi", "vi"),
        REGULATOR_SUPPLY("vddio_hsic", "tegra-ehci.1"),
        REGULATOR_SUPPLY("vddio_hsic", "tegra-ehci.2"),
        REGULATOR_SUPPLY("vddio_hsic", "tegra-xhci"),
@@ -566,7 +566,7 @@ static struct regulator_consumer_supply palmas_smps8_supply[] = {
        REGULATOR_SUPPLY("avdd_plle", NULL),
        REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegradc.0"),
        REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegradc.1"),
-       REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegra_camera"),
+       REGULATOR_SUPPLY("avdd_csi_dsi_pll", "vi"),
        REGULATOR_SUPPLY("avdd_hdmi_pll", "tegradc.1"),
        REGULATOR_SUPPLY("avdd_usb_pll", "tegra-ehci.2"),
        REGULATOR_SUPPLY("avddio_usb", "tegra-ehci.2"),
index 2883277..7ccbfe5 100644 (file)
@@ -402,13 +402,6 @@ static struct platform_device dalmore_audio_device = {
        },
 };
 
-#ifndef CONFIG_USE_OF
-static struct platform_device tegra_camera = {
-       .name = "tegra_camera",
-       .id = -1,
-};
-#endif
-
 static struct platform_device *dalmore_devices[] __initdata = {
        &tegra_pmu_device,
        &tegra_rtc_device,
@@ -416,9 +409,6 @@ static struct platform_device *dalmore_devices[] __initdata = {
 #if defined(CONFIG_TEGRA_AVP)
        &tegra_avp_device,
 #endif
-#ifndef CONFIG_USE_OF
-       &tegra_camera,
-#endif
 #if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
        &tegra11_se_device,
 #endif
index f42ed09..a5a69c4 100644 (file)
@@ -85,7 +85,7 @@ static struct regulator_consumer_supply palmas_smps8_supply[] = {
        REGULATOR_SUPPLY("pwrdet_uart", NULL),
        REGULATOR_SUPPLY("vddio_gmi", NULL),
        REGULATOR_SUPPLY("pwrdet_nand", NULL),
-       REGULATOR_SUPPLY("vddio_cam", "tegra_camera"),
+       REGULATOR_SUPPLY("vddio_cam", "vi"),
        REGULATOR_SUPPLY("pwrdet_cam", NULL),
        REGULATOR_SUPPLY("vdd_gps", NULL),
        REGULATOR_SUPPLY("vdd_nfc", NULL),
@@ -129,7 +129,7 @@ static struct regulator_consumer_supply palmas_ldo1_supply[] = {
        REGULATOR_SUPPLY("avdd_hdmi_pll", "tegradc.1"),
        REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegradc.0"),
        REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegradc.1"),
-       REGULATOR_SUPPLY("avdd_csi_dsi_pll", "tegra_camera"),
+       REGULATOR_SUPPLY("avdd_csi_dsi_pll", "vi"),
        REGULATOR_SUPPLY("avdd_pllm", NULL),
        REGULATOR_SUPPLY("avdd_pllu", NULL),
        REGULATOR_SUPPLY("avdd_plla_p_c", NULL),
@@ -145,7 +145,7 @@ static struct regulator_consumer_supply palmas_ldo2_supply[] = {
 static struct regulator_consumer_supply palmas_ldo3_supply[] = {
        REGULATOR_SUPPLY("avdd_dsi_csi", "tegradc.0"),
        REGULATOR_SUPPLY("avdd_dsi_csi", "tegradc.1"),
-       REGULATOR_SUPPLY("avdd_dsi_csi", "tegra_camera"),
+       REGULATOR_SUPPLY("avdd_dsi_csi", "vi"),
        REGULATOR_SUPPLY("vddio_hsic", "tegra-ehci.1"),
        REGULATOR_SUPPLY("vddio_hsic", "tegra-ehci.2"),
        REGULATOR_SUPPLY("vddio_hsic", "tegra-xhci"),
index 30c9faa..0426fe7 100644 (file)
@@ -545,13 +545,6 @@ static struct platform_device pluto_audio_aic326x_device = {
        },
 };
 
-#ifndef CONFIG_USE_OF
-static struct platform_device tegra_camera = {
-       .name = "tegra_camera",
-       .id = -1,
-};
-#endif
-
 static struct tegra_spi_device_controller_data dev_bdata = {
        .rx_clk_tap_delay = 0,
        .tx_clk_tap_delay = 0,
@@ -568,7 +561,6 @@ static struct spi_board_info aic326x_spi_board_info[] = {
        },
 };
 
-
 #ifdef CONFIG_MHI_NETDEV
 struct platform_device mhi_netdevice0 = {
        .name = "mhi_net_device",
@@ -583,9 +575,6 @@ static struct platform_device *pluto_devices[] __initdata = {
 #if defined(CONFIG_TEGRA_AVP)
        &tegra_avp_device,
 #endif
-#ifndef CONFIG_USE_OF
-       &tegra_camera,
-#endif
 #if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
        &tegra11_se_device,
 #endif
index 868db81..dd077d5 100644 (file)
@@ -6539,8 +6539,8 @@ struct clk tegra_list_clks[] = {
        PERIPH_CLK("uarte",     "tegra_uart.4",         NULL,   66,     0x1c4,  800000000, mux_pllp_pllc_pllm_clkm,     MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB),
        PERIPH_CLK("3d",        "3d",                   NULL,   24,     0x158,  700000000, mux_pllm_pllc2_c_c3_pllp_plla,       MUX | MUX8 | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
        PERIPH_CLK("2d",        "2d",                   NULL,   21,     0x15c,  700000000, mux_pllm_pllc2_c_c3_pllp_plla,       MUX | MUX8 | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
-       PERIPH_CLK_EX("vi",     "tegra_camera",         "vi",   20,     0x148,  425000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops),
-       PERIPH_CLK("vi_sensor", "tegra_camera",         "vi_sensor",    20,     0x1a8,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_NO_RESET),
+       PERIPH_CLK_EX("vi",     "vi",                   "vi",   20,     0x148,  425000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops),
+       PERIPH_CLK("vi_sensor", "vi",                   "vi_sensor",    20,     0x1a8,  150000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | PERIPH_NO_RESET),
        PERIPH_CLK("epp",       "epp",                  NULL,   19,     0x16c,  700000000, mux_pllm_pllc2_c_c3_pllp_plla,       MUX | MUX8 | DIV_U71 | DIV_U71_INT),
 #ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
        PERIPH_CLK("msenc",     "msenc",                NULL,   60,     0x170,  600000000, mux_pllm_pllc_pllp_plla,     MUX | DIV_U71 | DIV_U71_INT),
@@ -6560,12 +6560,12 @@ struct clk tegra_list_clks[] = {
        PERIPH_CLK_EX("dsib",   "tegradc.1",            "dsib", 82,     0x4b8,  500000000, mux_plld_out0_plld2_out0,    MUX | PLLD,     &tegra_dsi_clk_ops),
        PERIPH_CLK("dsi1-fixed", "tegradc.0",           "dsi-fixed",    0,      0,      108000000, mux_pllp_out3,       PERIPH_NO_ENB),
        PERIPH_CLK("dsi2-fixed", "tegradc.1",           "dsi-fixed",    0,      0,      108000000, mux_pllp_out3,       PERIPH_NO_ENB),
-       PERIPH_CLK("csi",       "tegra_camera",         "csi",  52,     0,      102000000, mux_pllp_out3,               0),
-       PERIPH_CLK("isp",       "tegra_camera",         "isp",  23,     0,      150000000, mux_clk_m,                   0), /* same frequency as VI */
-       PERIPH_CLK("csus",      "tegra_camera",         "csus", 92,     0,      150000000, mux_clk_m,                   PERIPH_NO_RESET),
-       PERIPH_CLK("cilab",     "tegra_camera",         "cilab", 144,   0x614,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
-       PERIPH_CLK("cilcd",     "tegra_camera",         "cilcd", 145,   0x618,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
-       PERIPH_CLK("cile",      "tegra_camera",         "cile",  146,   0x61c,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
+       PERIPH_CLK("csi",       "vi",                   "csi",  52,     0,      102000000, mux_pllp_out3,               0),
+       PERIPH_CLK("isp",       "vi",                   "isp",  23,     0,      150000000, mux_clk_m,                   0), /* same frequency as VI */
+       PERIPH_CLK("csus",      "vi",                   "csus", 92,     0,      150000000, mux_clk_m,                   PERIPH_NO_RESET),
+       PERIPH_CLK("cilab",     "vi",                   "cilab", 144,   0x614,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
+       PERIPH_CLK("cilcd",     "vi",                   "cilcd", 145,   0x618,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
+       PERIPH_CLK("cile",      "vi",                   "cile",  146,   0x61c,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
        PERIPH_CLK("dsialp",    "tegradc.0",            "dsialp", 147,  0x620,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
        PERIPH_CLK("dsiblp",    "tegradc.1",            "dsiblp", 148,  0x624,  102000000, mux_pllp_pllc_clkm,          MUX | DIV_U71),
 
@@ -6622,7 +6622,7 @@ struct clk tegra_list_clks[] = {
        SHARED_CLK("msenc.emc", "tegra_msenc",          "emc",  &tegra_clk_emc, NULL, 0, SHARED_BW),
        SHARED_CLK("tsec.emc",  "tegra_tsec",           "emc",  &tegra_clk_emc, NULL, 0, 0),
        SHARED_CLK("sdmmc4.emc", "sdhci-tegra.3",       "emc",  &tegra_clk_emc, NULL, 0, 0),
-       SHARED_CLK("camera.emc", "tegra_camera",        "emc",  &tegra_clk_emc, NULL, 0, SHARED_BW),
+       SHARED_CLK("camera.emc", "vi",                  "emc",  &tegra_clk_emc, NULL, 0, SHARED_BW),
        SHARED_CLK("iso.emc",   "iso",                  "emc",  &tegra_clk_emc, NULL, 0, SHARED_BW),
        SHARED_CLK("floor.emc", "floor.emc",            NULL,   &tegra_clk_emc, NULL, 0, 0),
        SHARED_CLK("override.emc", "override.emc",      NULL,   &tegra_clk_emc, NULL, 0, SHARED_OVERRIDE),
index 9bde762..8d59c89 100644 (file)
@@ -2,15 +2,6 @@ source "drivers/media/video/tegra/avp/Kconfig"
 source "drivers/media/video/tegra/mediaserver/Kconfig"
 source "drivers/media/video/tegra/nvavp/Kconfig"
 
-config TEGRA_CAMERA
-        bool "Enable support for tegra camera/isp hardware"
-        depends on ARCH_TEGRA
-        default y
-        help
-          Enables support for the Tegra camera interface
-
-          If unsure, say Y
-
 config TEGRA_DTV
         bool "Enable support for tegra dtv interface"
         depends on ARCH_TEGRA
index 20aab7a..699c095 100644 (file)
@@ -8,7 +8,6 @@ obj-y                           += avp/
 obj-$(CONFIG_TEGRA_MEDIASERVER)        += mediaserver/
 obj-$(CONFIG_TEGRA_NVAVP)      += nvavp/
 obj-$(CONFIG_TEGRA_DTV)                += tegra_dtv.o
-obj-$(CONFIG_TEGRA_CAMERA)     += tegra_camera.o
 obj-$(CONFIG_VIDEO_AR0832)     += ar0832_main.o
 obj-$(CONFIG_VIDEO_OV5650)     += ov5650.o
 obj-$(CONFIG_VIDEO_OV5640)     += ov5640.o
@@ -27,4 +26,3 @@ obj-$(CONFIG_VIDEO_AD5816)    += ad5816.o
 obj-$(CONFIG_VIDEO_IMX091)     += imx091.o
 obj-$(CONFIG_VIDEO_IMX132)     += imx132.o
 obj-$(CONFIG_DEBUG_FS)         += nvc_debugfs.o
-
index f545317..1ef23a4 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/module.h>
 
 #include <media/ov5650.h>
-#include <media/tegra_camera.h>
+#include <video/tegra_camera.h>
 
 #define SIZEOF_I2C_TRANSBUF 32
 
index 9d7c0dc..ae700b1 100644 (file)
@@ -230,3 +230,11 @@ config TEGRA_HDMI_74MHZ_LIMIT
 
 endif
 
+config TEGRA_CAMERA
+       bool "Enable support for tegra camera/isp hardware"
+       depends on ARCH_TEGRA
+       default y
+       help
+         Enables support for the Tegra camera interface
+
+         If unsure, say Y
index ce581d2..1db5abc 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_TEGRA_GRHOST) += host/
 obj-$(CONFIG_TEGRA_DC) += dc/
 obj-$(CONFIG_FB_TEGRA) += fb.o
 obj-$(CONFIG_TEGRA_NVMAP) += nvmap/
+obj-$(CONFIG_TEGRA_CAMERA) += camera/
diff --git a/drivers/video/tegra/camera/Makefile b/drivers/video/tegra/camera/Makefile
new file mode 100644 (file)
index 0000000..1f3930d
--- /dev/null
@@ -0,0 +1,7 @@
+GCOV_PROFILE := y
+EXTRA_CFLAGS += -Idrivers/video/tegra/host
+
+obj-y += camera.o
+obj-y += camera_power.o
+obj-y += camera_emc.o
+obj-y += camera_clk.o
diff --git a/drivers/video/tegra/camera/camera.c b/drivers/video/tegra/camera/camera.c
new file mode 100644 (file)
index 0000000..9264d8f
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * drivers/video/tegra/camera/camera.c
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "camera_priv_defs.h"
+#include "camera_clk.h"
+#include "camera_power.h"
+#include "camera_emc.h"
+
+#define TEGRA_CAMERA_NAME "tegra_camera"
+
+static struct camera_clk tegra_camera_clk[] = {
+       { CAMERA_ISP_CLK, "isp"},
+       { CAMERA_VI_CLK, "vi"},
+       { CAMERA_VI_SENSOR_CLK, "vi_sensor"},
+       { CAMERA_CSUS_CLK, "csus"},
+       { CAMERA_CSI_CLK, "csi"},
+       { CAMERA_EMC_CLK, "emc"},
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+       { CAMERA_CILAB_CLK, "cilab"},
+       { CAMERA_CILCD_CLK, "cilcd"},
+       { CAMERA_CILE_CLK, "cile"},
+       { CAMERA_PLL_D2_CLK, "pll_d2"}
+#endif
+};
+
+static long tegra_camera_ioctl(struct file *file,
+                              unsigned int cmd, unsigned long arg)
+{
+       uint id;
+       struct tegra_camera *camera = file->private_data;
+
+       /* first element of arg must be u32 with id of module to talk to */
+       if (copy_from_user(&id, (const void __user *)arg, sizeof(uint))) {
+               dev_err(camera->dev,
+                               "%s: Failed to copy arg from user", __func__);
+               return -EFAULT;
+       }
+
+       if (id >= TEGRA_CAMERA_MODULE_MAX) {
+               dev_err(camera->dev,
+                               "%s: Invalid id to tegra isp ioctl%d\n",
+                               __func__, id);
+               return -EINVAL;
+       }
+
+       switch (cmd) {
+       /*
+        * Clock enable/disable and reset should be handled in kernel.
+        * In order to support legacy code in user space, we don't remove
+        * these IOCTL.
+        */
+       case TEGRA_CAMERA_IOCTL_ENABLE:
+       case TEGRA_CAMERA_IOCTL_DISABLE:
+       case TEGRA_CAMERA_IOCTL_RESET:
+               return 0;
+       case TEGRA_CAMERA_IOCTL_CLK_SET_RATE:
+       {
+               int ret;
+
+               if (copy_from_user(&camera->info, (const void __user *)arg,
+                                  sizeof(struct tegra_camera_clk_info))) {
+                       dev_err(camera->dev,
+                               "%s: Failed to copy arg from user\n", __func__);
+                       return -EFAULT;
+               }
+               ret = tegra_camera_clk_set_rate(camera);
+               if (ret)
+                       return ret;
+               if (copy_to_user((void __user *)arg, &camera->info,
+                                sizeof(struct tegra_camera_clk_info))) {
+                       dev_err(camera->dev,
+                               "%s: Failed to copy arg to user\n", __func__);
+                       return -EFAULT;
+               }
+               return 0;
+       }
+       default:
+               dev_err(camera->dev,
+                               "%s: Unknown tegra_camera ioctl.\n", __func__);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int tegra_camera_open(struct inode *inode, struct file *file)
+{
+       int ret;
+       struct miscdevice *miscdev = file->private_data;
+       struct tegra_camera *camera = container_of(miscdev,
+                                               struct tegra_camera,
+                                               misc_dev);
+
+       dev_info(camera->dev, "%s: ++\n", __func__);
+
+       if (atomic_xchg(&camera->in_use, 1))
+               return -EBUSY;
+
+       file->private_data = camera;
+
+       mutex_lock(&camera->tegra_camera_lock);
+
+       /* turn on CSI regulator */
+       ret = tegra_camera_power_on(camera);
+       if (ret)
+               goto power_on_fail;
+       /* set EMC request */
+       ret = tegra_camera_enable_emc(camera);
+       if (ret)
+               goto enable_emc_fail;
+       /* enable camera HW clock */
+       ret = tegra_camera_enable_clk(camera);
+       if (ret)
+               goto enable_clk_fail;
+
+       mutex_unlock(&camera->tegra_camera_lock);
+
+       return 0;
+
+enable_clk_fail:
+       tegra_camera_disable_emc(camera);
+enable_emc_fail:
+       tegra_camera_power_off(camera);
+power_on_fail:
+       mutex_unlock(&camera->tegra_camera_lock);
+       return ret;
+}
+
+static int tegra_camera_release(struct inode *inode, struct file *file)
+{
+       int ret = 0;
+       struct tegra_camera *camera = file->private_data;
+
+       dev_info(camera->dev, "%s++\n", __func__);
+
+       mutex_lock(&camera->tegra_camera_lock);
+       /* disable HW clock */
+       ret = tegra_camera_disable_clk(camera);
+       if (ret)
+               goto release_exit;
+       /* nullify EMC request */
+       ret = tegra_camera_disable_emc(camera);
+       if (ret)
+               goto release_exit;
+       /* turn off CSI regulator */
+       ret = tegra_camera_power_off(camera);
+       if (ret)
+               goto release_exit;
+
+release_exit:
+       mutex_unlock(&camera->tegra_camera_lock);
+       WARN_ON(!atomic_xchg(&camera->in_use, 0));
+       return 0;
+}
+
+static const struct file_operations tegra_camera_fops = {
+       .owner = THIS_MODULE,
+       .open = tegra_camera_open,
+       .unlocked_ioctl = tegra_camera_ioctl,
+       .release = tegra_camera_release,
+};
+
+static int tegra_camera_clk_get(struct platform_device *ndev, const char *name,
+                               struct clk **clk)
+{
+       *clk = clk_get(&ndev->dev, name);
+       if (IS_ERR_OR_NULL(*clk)) {
+               dev_err(&ndev->dev, "%s: unable to get clock for %s\n",
+                       __func__, name);
+               *clk = NULL;
+               return PTR_ERR(*clk);
+       }
+       return 0;
+}
+
+struct tegra_camera *tegra_camera_register(struct platform_device *ndev)
+{
+       struct tegra_camera *camera = NULL;
+       int ret = 0;
+       int i;
+
+       dev_info(&ndev->dev, "%s: ++\n", __func__);
+
+       camera = kzalloc(sizeof(struct tegra_camera), GFP_KERNEL);
+       if (!camera) {
+               dev_err(&ndev->dev, "can't allocate memory for tegra_camera\n");
+               return camera;
+       }
+
+       mutex_init(&camera->tegra_camera_lock);
+
+       /* Powergate VE when boot */
+       mutex_lock(&camera->tegra_camera_lock);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       ret = tegra_camera_powergate_init(camera);
+       if (ret)
+               goto regulator_fail;
+#endif
+       mutex_unlock(&camera->tegra_camera_lock);
+
+       camera->dev = &ndev->dev;
+
+       /* Get regulator pointer */
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       camera->reg = regulator_get(&ndev->dev, "vcsi");
+#else
+       camera->reg = regulator_get(&ndev->dev, "avdd_dsi_csi");
+#endif
+
+       if (IS_ERR_OR_NULL(camera->reg)) {
+               ret = -ENODEV;
+               if (camera->reg == ERR_PTR(-ENODEV)) {
+                       camera->reg = NULL;
+                       dev_info(&ndev->dev,
+                               "%s: no regulator device, overriding\n",
+                                                       __func__);
+               } else {
+                       dev_err(&ndev->dev, "%s: couldn't get regulator\n",
+                                                       __func__);
+                       goto regulator_fail;
+               }
+       }
+
+       camera->misc_dev.minor = MISC_DYNAMIC_MINOR;
+       camera->misc_dev.name = TEGRA_CAMERA_NAME;
+       camera->misc_dev.fops = &tegra_camera_fops;
+       camera->misc_dev.parent = &ndev->dev;
+       ret = misc_register(&camera->misc_dev);
+       if (ret) {
+               dev_err(&ndev->dev, "%s: unable to register misc device!\n",
+                       TEGRA_CAMERA_NAME);
+               goto misc_register_fail;
+       }
+
+       for (i = 0; i < CAMERA_CLK_MAX; i++) {
+               ret = tegra_camera_clk_get(ndev, tegra_camera_clk[i].name,
+                               &camera->clk[tegra_camera_clk[i].index]);
+               if (ret)
+                       goto clk_get_fail;
+       }
+
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+       /*
+        * Dedicated bw is what VI could ask for at most.
+        * Assume that preview has 3M@30fps and video has 8M@30fps
+        * Total = 3M * 30fps * 2Bpp + 8M * 30fps * 1.5Bpp
+        *       = 540MBps
+        * This number can be changed if VI requests more than this.
+        *
+        */
+       camera->isomgr_handle = tegra_isomgr_register(TEGRA_ISO_CLIENT_VI_0,
+                                       540000, /* dedicated bw, KBps*/
+                                       NULL,   /* tegra_isomgr_renegotiate */
+                                       NULL);  /* *priv */
+       if (!camera->isomgr_handle) {
+               dev_err(&ndev->dev, "%s: unable to register isomgr\n",
+                                       __func__);
+               goto clk_get_fail;
+       }
+#endif
+
+       return camera;
+
+clk_get_fail:
+       for (; i > 0; i--)
+               clk_put(camera->clk[i-1]);
+       misc_deregister(&camera->misc_dev);
+misc_register_fail:
+       regulator_put(camera->reg);
+regulator_fail:
+       kfree(camera);
+       camera = NULL;
+       return camera;
+}
+
+int tegra_camera_unregister(struct tegra_camera *camera)
+{
+       dev_info(camera->dev, "%s: ++\n", __func__);
+
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+       /*
+        * Return memory bandwidth to isomgr.
+        * If bandwidth is zero, then latency will be ignored
+        * in tegra_isomgr_reserve().
+        */
+       {
+               int ret = 0;
+
+               ret = tegra_isomgr_reserve(camera->isomgr_handle,
+                                       0,      /* KB/sec */
+                                       0);     /* usec */
+               if (!ret)
+                       return -ENOMEM;
+
+               tegra_isomgr_unregister(camera->isomgr_handle);
+               camera->isomgr_handle = NULL;
+       }
+#endif
+       kfree(camera);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+int tegra_camera_suspend(struct tegra_camera *camera)
+{
+       int ret = 0;
+
+       dev_dbg(camera->dev, "%s: ++\n", __func__);
+       mutex_lock(&camera->tegra_camera_lock);
+       if (camera->power_on) {
+               ret = -EBUSY;
+               dev_err(camera->dev,
+               "tegra_camera cannot suspend, "
+               "application is holding on to camera.\n");
+       }
+       mutex_unlock(&camera->tegra_camera_lock);
+
+       return ret;
+}
+
+int tegra_camera_resume(struct tegra_camera *camera)
+{
+       dev_info(camera->dev, "%s: ++\n", __func__);
+       return 0;
+}
+#endif
diff --git a/drivers/video/tegra/camera/camera_clk.c b/drivers/video/tegra/camera/camera_clk.c
new file mode 100644 (file)
index 0000000..d3668c9
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * drivers/video/tegra/camera/camera_clk.c
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "camera_clk.h"
+
+int tegra_camera_enable_clk(struct tegra_camera *camera)
+{
+       int i;
+       for (i = 0; i < CAMERA_CLK_MAX; i++)
+               clk_prepare_enable(camera->clk[i]);
+       return 0;
+}
+
+int tegra_camera_disable_clk(struct tegra_camera *camera)
+{
+       int i;
+       for (i = CAMERA_CLK_MAX; i > 0; i--)
+               clk_prepare_enable(camera->clk[i-1]);
+       return 0;
+}
+
+int tegra_camera_clk_set_rate(struct tegra_camera *camera)
+{
+       struct clk *clk, *clk_parent;
+       struct tegra_camera_clk_info *info = &camera->info;
+       unsigned long parent_rate, parent_div_rate, parent_div_rate_pre;
+
+       if (!info) {
+               dev_err(camera->dev,
+                               "%s: no clock info %d\n",
+                               __func__, info->id);
+               return -EINVAL;
+       }
+
+       if (info->id != TEGRA_CAMERA_MODULE_VI &&
+               info->id != TEGRA_CAMERA_MODULE_EMC) {
+               dev_err(camera->dev,
+                               "%s: set rate only aplies to vi module %d\n",
+                               __func__, info->id);
+               return -EINVAL;
+       }
+
+       switch (info->clk_id) {
+       case TEGRA_CAMERA_VI_CLK:
+               clk = camera->clk[CAMERA_VI_CLK];
+               break;
+       case TEGRA_CAMERA_VI_SENSOR_CLK:
+               clk = camera->clk[CAMERA_VI_SENSOR_CLK];
+               break;
+       case TEGRA_CAMERA_EMC_CLK:
+               clk = camera->clk[CAMERA_EMC_CLK];
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+               {
+                       /*
+                        * User space assumes that HW emc controller is 4
+                        * byte-wide DDR controller.
+                        * Emc bandwidth needs to be calcaluated using input emc
+                        * freq first, and then real emc freq will
+                        * be calculated using tegra_emc API.
+                        * tegra_emc_bw_to_freq_req takes HW difference
+                        * into consideration.
+                        * bw param in tegra_emc_bw_to_freq_req() is in KHz.
+                        */
+                       unsigned long bw = (info->rate * 8) >> 10;
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+                       int ret = 0;
+#endif
+                       dev_dbg(camera->dev, "%s: emc_clk rate=%lu\n",
+                               __func__, info->rate);
+                       clk_set_rate(clk,
+                                       tegra_emc_bw_to_freq_req(bw) << 10);
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+                       /*
+                        * There is no way to figure out what latency
+                        * can be tolerated in VI without reading VI
+                        * registers for now. 3 usec is minimum time
+                        * to switch PLL source. Let's put 4 usec as
+                        * latency for now.
+                        */
+                       ret = tegra_isomgr_reserve(camera->isomgr_handle,
+                                       bw,     /* KB/sec */
+                                       4);     /* usec */
+                       if (!ret)
+                               return -ENOMEM;
+
+                       ret = tegra_isomgr_realize(camera->isomgr_handle);
+                       if (!ret)
+                               return -ENOMEM;
+#endif
+               }
+#endif
+               goto set_rate_end;
+       default:
+               dev_err(camera->dev,
+                               "%s: invalid clk id for set rate %d\n",
+                               __func__, info->clk_id);
+               return -EINVAL;
+       }
+
+       clk_parent = clk_get_parent(clk);
+       parent_rate = clk_get_rate(clk_parent);
+       dev_dbg(camera->dev, "%s: clk_id=%d, parent_rate=%lu, clk_rate=%lu\n",
+                       __func__, info->clk_id, parent_rate, info->rate);
+       parent_div_rate = parent_rate;
+       parent_div_rate_pre = parent_rate;
+
+       /*
+        * The requested clock rate from user space should be respected.
+        * This loop is to search the clock rate that is higher than requested
+        * clock.
+        */
+       while (parent_div_rate >= info->rate) {
+               parent_div_rate_pre = parent_div_rate;
+               parent_div_rate = clk_round_rate(clk, parent_div_rate-1);
+       }
+
+       dev_dbg(camera->dev, "%s: set_rate=%lu",
+                       __func__, parent_div_rate_pre);
+
+       clk_set_rate(clk, parent_div_rate_pre);
+
+       if (info->clk_id == TEGRA_CAMERA_VI_CLK) {
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+               {
+                       u32 val;
+                       void __iomem *apb_misc =
+                               IO_ADDRESS(TEGRA_APB_MISC_BASE);
+                       val = readl(apb_misc + 0x42c);
+                       writel(val | 0x1, apb_misc + 0x42c);
+               }
+#endif
+               if (info->flag == TEGRA_CAMERA_ENABLE_PD2VI_CLK) {
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+                       tegra_clk_cfg_ex(camera->clk[CAMERA_PLL_D2_CLK],
+                                               TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
+#else
+               /*
+                * bit 25: 0 = pd2vi_Clk, 1 = vi_sensor_clk
+                * bit 24: 0 = internal clock, 1 = external clock(pd2vi_clk)
+                */
+                       tegra_clk_cfg_ex(clk, TEGRA_CLK_VI_INP_SEL, 2);
+#endif
+               }
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+               else {
+                       tegra_clk_cfg_ex(camera->clk[CAMERA_PLL_D2_CLK],
+                                               TEGRA_CLK_PLLD_CSI_OUT_ENB, 0);
+               }
+#endif
+       }
+
+set_rate_end:
+       info->rate = clk_get_rate(clk);
+       dev_dbg(camera->dev, "%s: get_rate=%lu",
+                       __func__, info->rate);
+       return 0;
+}
diff --git a/drivers/video/tegra/camera/camera_clk.h b/drivers/video/tegra/camera/camera_clk.h
new file mode 100644 (file)
index 0000000..19fc9db
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * drivers/video/tegra/camera/camera_clk.h
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_CLK_H
+#define __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_CLK_H
+#include "camera_priv_defs.h"
+
+int tegra_camera_enable_clk(struct tegra_camera *camera);
+int tegra_camera_disable_clk(struct tegra_camera *camera);
+int tegra_camera_clk_set_rate(struct tegra_camera *camera);
+
+#endif
diff --git a/drivers/video/tegra/camera/camera_emc.c b/drivers/video/tegra/camera/camera_emc.c
new file mode 100644 (file)
index 0000000..44208c1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * drivers/video/tegra/camera/camera_emc.c
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "camera_emc.h"
+
+int tegra_camera_enable_emc(struct tegra_camera *camera)
+{
+       int ret = tegra_emc_disable_eack();
+
+       dev_dbg(camera->dev, "%s++\n", __func__);
+       clk_prepare_enable(camera->clk[CAMERA_EMC_CLK]);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       clk_set_rate(camera->clk[TEGRA_CAMERA_EMC_CLK], 300000000);
+#endif
+       return ret;
+}
+
+int tegra_camera_disable_emc(struct tegra_camera *camera)
+{
+       dev_dbg(camera->dev, "%s++\n", __func__);
+       clk_disable_unprepare(camera->clk[CAMERA_EMC_CLK]);
+       return tegra_emc_enable_eack();
+}
diff --git a/drivers/video/tegra/camera/camera_emc.h b/drivers/video/tegra/camera/camera_emc.h
new file mode 100644 (file)
index 0000000..8ee7d05
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * drivers/video/tegra/camera/camera_emc.h
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_EMC_H
+#define __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_EMC_H
+#include "camera_priv_defs.h"
+
+int tegra_camera_enable_emc(struct tegra_camera *camera);
+int tegra_camera_disable_emc(struct tegra_camera *camera);
+
+#endif
diff --git a/drivers/video/tegra/camera/camera_power.c b/drivers/video/tegra/camera/camera_power.c
new file mode 100644 (file)
index 0000000..8a6d8af
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * drivers/video/tegra/camera/camera_power.c
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "camera_power.h"
+
+int tegra_camera_power_on(struct tegra_camera *camera)
+{
+       int ret = 0;
+       dev_dbg(camera->dev, "%s++\n", __func__);
+
+       /* Enable external power */
+       if (camera->reg) {
+               ret = regulator_enable(camera->reg);
+               if (ret) {
+                       dev_err(camera->dev,
+                               "%s: enable csi regulator failed.\n",
+                               __func__);
+                       return ret;
+               }
+       }
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       /* Unpowergate VE */
+       ret = tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
+       if (ret)
+               dev_err(camera->dev,
+                       "%s: unpowergate failed.\n",
+                       __func__);
+#endif
+       camera->power_on = 1;
+       return ret;
+}
+
+int tegra_camera_power_off(struct tegra_camera *camera)
+{
+       int ret = 0;
+
+       dev_dbg(camera->dev, "%s++\n", __func__);
+
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       /* Powergate VE */
+       ret = tegra_powergate_partition(TEGRA_POWERGATE_VENC);
+       if (ret)
+               dev_err(camera->dev,
+                       "%s: powergate failed.\n",
+                       __func__);
+#endif
+       /* Disable external power */
+       if (camera->reg) {
+               ret = regulator_disable(camera->reg);
+               if (ret) {
+                       dev_err(camera->dev,
+                               "%s: disable csi regulator failed.\n",
+                               __func__);
+                       return ret;
+               }
+       }
+       camera->power_on = 0;
+       return ret;
+}
+
+int tegra_camera_powergate_init(struct tegra_camera *camera)
+{
+       int ret = 0;
+
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       ret = tegra_powergate_partition(TEGRA_POWERGATE_VENC);
+       if (ret)
+               dev_err(camera->dev, "%s: powergate failed.\n", __func__);
+#endif
+       return ret;
+}
diff --git a/drivers/video/tegra/camera/camera_power.h b/drivers/video/tegra/camera/camera_power.h
new file mode 100644 (file)
index 0000000..4628501
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * drivers/video/tegra/camera/camera_power.h
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_POWER_H
+#define __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_POWER_H
+#include "camera_priv_defs.h"
+
+int tegra_camera_power_on(struct tegra_camera *camera);
+int tegra_camera_power_off(struct tegra_camera *camera);
+int tegra_camera_powergate_init(struct tegra_camera *camera);
+
+#endif
+
diff --git a/drivers/video/tegra/camera/camera_priv_defs.h b/drivers/video/tegra/camera/camera_priv_defs.h
new file mode 100644 (file)
index 0000000..19dbb7c
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * drivers/video/tegra/camera/camera_priv_defs.h
+ *
+ * Copyright (C) 2013 Nvidia Corp
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_PRIV_DEFS_H
+#define __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_PRIV_DEFS_H
+
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+
+#include <mach/powergate.h>
+#include <mach/clk.h>
+#include <mach/mc.h>
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+#include <mach/isomgr.h>
+#endif
+
+#include <video/tegra_camera.h>
+
+
+/*
+ * CAMERA_*_CLK is only for internal driver use.
+ * TEGRA_CAMERA_*_CLK is enum used between driver and user space.
+ * TEGRA_CAMERA_*_CLK is defined in tegra_camera.h
+ */
+enum {
+       CAMERA_VI_CLK,
+       CAMERA_VI_SENSOR_CLK,
+       CAMERA_EMC_CLK,
+       CAMERA_ISP_CLK,
+       CAMERA_CSUS_CLK,
+       CAMERA_CSI_CLK,
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+       CAMERA_CILAB_CLK,
+       CAMERA_CILCD_CLK,
+       CAMERA_CILE_CLK,
+       CAMERA_PLL_D2_CLK,
+#endif
+       CAMERA_CLK_MAX,
+};
+
+struct tegra_camera {
+       struct device *dev;
+       struct miscdevice misc_dev;
+       struct clk *clk[CAMERA_CLK_MAX];
+       struct regulator *reg;
+       struct tegra_camera_clk_info info;
+       struct mutex tegra_camera_lock;
+       atomic_t in_use;
+       int power_on;
+#ifdef CONFIG_ARCH_TEGRA_11x_SOC
+       tegra_isomgr_handle isomgr_handle;
+#endif
+};
+
+struct camera_clk {
+       int index;
+       char *name;
+};
+
+struct tegra_camera *tegra_camera_register(struct platform_device *ndev);
+int tegra_camera_unregister(struct tegra_camera *camera);
+#ifdef CONFIG_PM
+int tegra_camera_suspend(struct tegra_camera *camera);
+int tegra_camera_resume(struct tegra_camera *camera);
+#endif
+
+#endif
index 8c130e4..666cdfc 100644 (file)
@@ -1,5 +1,6 @@
 GCOV_PROFILE := y
 EXTRA_CFLAGS += -Idrivers/video/tegra/host
+EXTRA_CFLAGS += -Idrivers/video/tegra/camera
 
 nvhost-vi-objs  = \
                vi.o
index 446ca67..f18d9ce 100644 (file)
@@ -30,6 +30,7 @@
 #include "t20/t20.h"
 #include "t30/t30.h"
 #include "t114/t114.h"
+#include "vi.h"
 
 static struct of_device_id tegra_vi_of_match[] = {
        { .compatible = "nvidia,tegra20-vi",
@@ -44,6 +45,7 @@ static struct of_device_id tegra_vi_of_match[] = {
 static int vi_probe(struct platform_device *dev)
 {
        int err = 0;
+       struct vi *tegra_vi;
        struct nvhost_device_data *pdata = NULL;
 
        if (dev->dev.of_node) {
@@ -61,39 +63,99 @@ static int vi_probe(struct platform_device *dev)
                return -ENODATA;
        }
 
+       dev_info(&dev->dev, "%s: ++\n", __func__);
+       tegra_vi = kzalloc(sizeof(struct vi), GFP_KERNEL);
+       if (!tegra_vi) {
+               dev_err(&dev->dev, "can't allocate memory for vi\n");
+               return -ENOMEM;
+       }
+
+       tegra_vi->ndev = dev;
+       pdata->private_data = tegra_vi;
+
+#ifdef CONFIG_TEGRA_CAMERA
+       tegra_vi->camera = tegra_camera_register(dev);
+       if (!tegra_vi->camera) {
+               dev_err(&dev->dev, "%s: can't register tegra_camera\n",
+                               __func__);
+               goto camera_register_fail;
+       }
+#endif
        pdata->pdev = dev;
        platform_set_drvdata(dev, pdata);
-
        err = nvhost_client_device_get_resources(dev);
        if (err)
-               return err;
+               goto camera_register_fail;
 
        err = nvhost_client_device_init(dev);
        if (err)
-               return err;
+               goto camera_register_fail;
 
        pm_runtime_use_autosuspend(&dev->dev);
        pm_runtime_set_autosuspend_delay(&dev->dev, 100);
        pm_runtime_enable(&dev->dev);
 
        return 0;
+
+camera_register_fail:
+       kfree(tegra_vi);
+       return err;
+
 }
 
 static int __exit vi_remove(struct platform_device *dev)
 {
-       /* Add clean-up */
+#ifdef CONFIG_TEGRA_CAMERA
+       int err = 0;
+       struct nvhost_device_data *pdata =
+               (struct nvhost_device_data *)dev->dev.platform_data;
+       struct vi *tegra_vi = (struct vi *)pdata->private_data;
+#endif
+
+       dev_info(&dev->dev, "%s: ++\n", __func__);
+
+#ifdef CONFIG_TEGRA_CAMERA
+       err = tegra_camera_unregister(tegra_vi->camera);
+       if (err)
+               return err;
+#endif
+
        return 0;
 }
 
 #ifdef CONFIG_PM
 static int vi_suspend(struct device *dev)
 {
+#ifdef CONFIG_TEGRA_CAMERA
+       struct nvhost_device_data *pdata =
+               (struct nvhost_device_data *)dev->platform_data;
+       struct vi *tegra_vi = (struct vi *)pdata->private_data;
+#endif
+
+       dev_info(dev, "%s: ++\n", __func__);
+
+#ifdef CONFIG_TEGRA_CAMERA
+       tegra_camera_suspend(tegra_vi->camera);
+#endif
+
        return nvhost_client_device_suspend(to_platform_device(dev));
 }
 
 static int vi_resume(struct device *dev)
 {
-       dev_info(dev, "resuming\n");
+#ifdef CONFIG_TEGRA_CAMERA
+       struct nvhost_device_data *pdata =
+               (struct nvhost_device_data *)dev->platform_data;
+
+       struct vi *tegra_vi = (struct vi *)pdata->private_data;
+#endif
+
+       dev_info(dev, "%s: ++\n", __func__);
+
+#ifdef CONFIG_TEGRA_CAMERA
+       tegra_camera_resume(tegra_vi->camera);
+#endif
+
        return 0;
 }
 
@@ -133,5 +195,5 @@ static void __exit vi_exit(void)
        platform_driver_unregister(&vi_driver);
 }
 
-module_init(vi_init);
+late_initcall(vi_init);
 module_exit(vi_exit);
diff --git a/drivers/video/tegra/host/vi/vi.h b/drivers/video/tegra/host/vi/vi.h
new file mode 100644 (file)
index 0000000..152043d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * drivers/video/tegra/host/vi/vi.h
+ *
+ * Tegra Graphics Host VI
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __NVHOST_VI_H__
+#define __NVHOST_VI_H__
+
+#include "camera_priv_defs.h"
+
+struct vi {
+       struct tegra_camera *camera;
+       struct platform_device *ndev;
+};
+
+#endif