/* * Copyright (c) 2013-2014, 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, * 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 . */ #include #include #include #include #include #include #include #include "nvhost_syncpt.h" #include "common.h" #define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 200 #define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200 #define TEGRA_VIP_H_ACTIVE_START 0x98 #define TEGRA_VIP_V_ACTIVE_START 0x10 /* Tegra CSI-MIPI registers. */ #define TEGRA_VI_OUT_1_INCR_SYNCPT 0x000 #define TEGRA_VI_OUT_1_INCR_SYNCPT_CNTRL 0x004 #define TEGRA_VI_OUT_1_INCR_SYNCPT_ERROR 0x008 #define TEGRA_VI_OUT_2_INCR_SYNCPT 0x020 #define TEGRA_VI_OUT_2_INCR_SYNCPT_CNTRL 0x024 #define TEGRA_VI_OUT_2_INCR_SYNCPT_ERROR 0x028 #define TEGRA_VI_MISC_INCR_SYNCPT 0x040 #define TEGRA_VI_MISC_INCR_SYNCPT_CNTRL 0x044 #define TEGRA_VI_MISC_INCR_SYNCPT_ERROR 0x048 #define TEGRA_VI_CONT_SYNCPT_OUT_1 0x060 #define TEGRA_VI_CONT_SYNCPT_OUT_2 0x064 #define TEGRA_VI_CONT_SYNCPT_VIP_VSYNC 0x068 #define TEGRA_VI_CONT_SYNCPT_VI2EPP 0x06c #define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_START 0x070 #define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END 0x074 #define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_START 0x078 #define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END 0x07c #define TEGRA_VI_CTXSW 0x080 #define TEGRA_VI_INTSTATUS 0x084 #define TEGRA_VI_VI_INPUT_CONTROL 0x088 #define TEGRA_VI_VI_CORE_CONTROL 0x08c #define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL 0x090 #define TEGRA_VI_VI_SECOND_OUTPUT_CONTROL 0x094 #define TEGRA_VI_HOST_INPUT_FRAME_SIZE 0x098 #define TEGRA_VI_HOST_H_ACTIVE 0x09c #define TEGRA_VI_HOST_V_ACTIVE 0x0a0 #define TEGRA_VI_VIP_H_ACTIVE 0x0a4 #define TEGRA_VI_VIP_V_ACTIVE 0x0a8 #define TEGRA_VI_VI_PEER_CONTROL 0x0ac #define TEGRA_VI_VI_DMA_SELECT 0x0b0 #define TEGRA_VI_HOST_DMA_WRITE_BUFFER 0x0b4 #define TEGRA_VI_HOST_DMA_BASE_ADDRESS 0x0b8 #define TEGRA_VI_HOST_DMA_WRITE_BUFFER_STATUS 0x0bc #define TEGRA_VI_HOST_DMA_WRITE_PEND_BUFCOUNT 0x0c0 #define TEGRA_VI_VB0_START_ADDRESS_FIRST 0x0c4 #define TEGRA_VI_VB0_BASE_ADDRESS_FIRST 0x0c8 #define TEGRA_VI_VB0_START_ADDRESS_U 0x0cc #define TEGRA_VI_VB0_BASE_ADDRESS_U 0x0d0 #define TEGRA_VI_VB0_START_ADDRESS_V 0x0d4 #define TEGRA_VI_VB0_BASE_ADDRESS_V 0x0d8 #define TEGRA_VI_VB_SCRATCH_ADDRESS_UV 0x0dc #define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE 0x0e0 #define TEGRA_VI_VB0_COUNT_FIRST 0x0e4 #define TEGRA_VI_VB0_SIZE_FIRST 0x0e8 #define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST 0x0ec #define TEGRA_VI_VB0_START_ADDRESS_SECOND 0x0f0 #define TEGRA_VI_VB0_BASE_ADDRESS_SECOND 0x0f4 #define TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE 0x0f8 #define TEGRA_VI_VB0_COUNT_SECOND 0x0fc #define TEGRA_VI_VB0_SIZE_SECOND 0x100 #define TEGRA_VI_VB0_BUFFER_STRIDE_SECOND 0x104 #define TEGRA_VI_H_LPF_CONTROL 0x108 #define TEGRA_VI_H_DOWNSCALE_CONTROL 0x10c #define TEGRA_VI_V_DOWNSCALE_CONTROL 0x110 #define TEGRA_VI_CSC_Y 0x114 #define TEGRA_VI_CSC_UV_R 0x118 #define TEGRA_VI_CSC_UV_G 0x11c #define TEGRA_VI_CSC_UV_B 0x120 #define TEGRA_VI_CSC_ALPHA 0x124 #define TEGRA_VI_HOST_VSYNC 0x128 #define TEGRA_VI_COMMAND 0x12c #define TEGRA_VI_HOST_FIFO_STATUS 0x130 #define TEGRA_VI_INTERRUPT_MASK 0x134 #define TEGRA_VI_INTERRUPT_TYPE_SELECT 0x138 #define TEGRA_VI_INTERRUPT_POLARITY_SELECT 0x13c #define TEGRA_VI_INTERRUPT_STATUS 0x140 #define TEGRA_VI_VIP_INPUT_STATUS 0x144 #define TEGRA_VI_VIDEO_BUFFER_STATUS 0x148 #define TEGRA_VI_SYNC_OUTPUT 0x14c #define TEGRA_VI_VVS_OUTPUT_DELAY 0x150 #define TEGRA_VI_PWM_CONTROL 0x154 #define TEGRA_VI_PWM_SELECT_PULSE_A 0x158 #define TEGRA_VI_PWM_SELECT_PULSE_B 0x15c #define TEGRA_VI_PWM_SELECT_PULSE_C 0x160 #define TEGRA_VI_PWM_SELECT_PULSE_D 0x164 #define TEGRA_VI_VI_DATA_INPUT_CONTROL 0x168 #define TEGRA_VI_PIN_INPUT_ENABLE 0x16c #define TEGRA_VI_PIN_OUTPUT_ENABLE 0x170 #define TEGRA_VI_PIN_INVERSION 0x174 #define TEGRA_VI_PIN_INPUT_DATA 0x178 #define TEGRA_VI_PIN_OUTPUT_DATA 0x17c #define TEGRA_VI_PIN_OUTPUT_SELECT 0x180 #define TEGRA_VI_RAISE_VIP_BUFFER_FIRST_OUTPUT 0x184 #define TEGRA_VI_RAISE_VIP_FRAME_FIRST_OUTPUT 0x188 #define TEGRA_VI_RAISE_VIP_BUFFER_SECOND_OUTPUT 0x18c #define TEGRA_VI_RAISE_VIP_FRAME_SECOND_OUTPUT 0x190 #define TEGRA_VI_RAISE_HOST_FIRST_OUTPUT 0x194 #define TEGRA_VI_RAISE_HOST_SECOND_OUTPUT 0x198 #define TEGRA_VI_RAISE_EPP 0x19c #define TEGRA_VI_CAMERA_CONTROL 0x1a0 #define TEGRA_VI_VI_ENABLE 0x1a4 #define TEGRA_VI_VI_ENABLE_2 0x1a8 #define TEGRA_VI_VI_RAISE 0x1ac #define TEGRA_VI_Y_FIFO_WRITE 0x1b0 #define TEGRA_VI_U_FIFO_WRITE 0x1b4 #define TEGRA_VI_V_FIFO_WRITE 0x1b8 #define TEGRA_VI_VI_MCCIF_FIFOCTRL 0x1bc #define TEGRA_VI_TIMEOUT_WCOAL_VI 0x1c0 #define TEGRA_VI_MCCIF_VIRUV_HP 0x1c4 #define TEGRA_VI_MCCIF_VIWSB_HP 0x1c8 #define TEGRA_VI_MCCIF_VIWU_HP 0x1cc #define TEGRA_VI_MCCIF_VIWV_HP 0x1d0 #define TEGRA_VI_MCCIF_VIWY_HP 0x1d4 #define TEGRA_VI_CSI_PPA_RAISE_FRAME_START 0x1d8 #define TEGRA_VI_CSI_PPA_RAISE_FRAME_END 0x1dc #define TEGRA_VI_CSI_PPB_RAISE_FRAME_START 0x1e0 #define TEGRA_VI_CSI_PBB_RAISE_FRAME_END 0x1e4 #define TEGRA_VI_CSI_PPA_H_ACTIVE 0x1e8 #define TEGRA_VI_CSI_PPA_V_ACTIVE 0x1ec #define TEGRA_VI_CSI_PPB_H_ACTIVE 0x1f0 #define TEGRA_VI_CSI_PPB_V_ACTIVE 0x1f4 #define TEGRA_VI_ISP_H_ACTIVE 0x1f8 #define TEGRA_VI_ISP_V_ACTIVE 0x1fc #define TEGRA_VI_STREAM_1_RESOURCE_DEFINE 0x200 #define TEGRA_VI_STREAM_2_RESOURCE_DEFINE 0x204 #define TEGRA_VI_RAISE_STREAM_1_DONE 0x208 #define TEGRA_VI_RAISE_STREAM_2_DONE 0x20c #define TEGRA_VI_TS_MODE 0x210 #define TEGRA_VI_TS_CONTROL 0x214 #define TEGRA_VI_TS_PACKET_COUNT 0x218 #define TEGRA_VI_TS_ERROR_COUNT 0x21c #define TEGRA_VI_TS_CPU_FLOW_CTL 0x220 #define TEGRA_VI_VB0_CHROMA_BUFFER_STRIDE_FIRST 0x224 #define TEGRA_VI_VB0_CHROMA_LINE_STRIDE_FIRST 0x228 #define TEGRA_VI_EPP_LINES_PER_BUFFER 0x22c #define TEGRA_VI_BUFFER_RELEASE_OUTPUT1 0x230 #define TEGRA_VI_BUFFER_RELEASE_OUTPUT2 0x234 #define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT1 0x238 #define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT2 0x23c #define TEGRA_VI_TERMINATE_BW_FIRST 0x240 #define TEGRA_VI_TERMINATE_BW_SECOND 0x244 #define TEGRA_VI_VB0_FIRST_BUFFER_ADDR_MODE 0x248 #define TEGRA_VI_VB0_SECOND_BUFFER_ADDR_MODE 0x24c #define TEGRA_VI_RESERVE 0x250 #define TEGRA_VI_RESERVE_1 0x254 #define TEGRA_VI_RESERVE_2 0x258 #define TEGRA_VI_RESERVE_3 0x25c #define TEGRA_VI_RESERVE_4 0x260 #define TEGRA_VI_MCCIF_VIRUV_HYST 0x264 #define TEGRA_VI_MCCIF_VIWSB_HYST 0x268 #define TEGRA_VI_MCCIF_VIWU_HYST 0x26c #define TEGRA_VI_MCCIF_VIWV_HYST 0x270 #define TEGRA_VI_MCCIF_VIWY_HYST 0x274 #define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x800 #define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x808 #define TEGRA_CSI_INPUT_STREAM_A_CONTROL 0x810 #define TEGRA_CSI_PIXEL_STREAM_A_CONTROL0 0x818 #define TEGRA_CSI_PIXEL_STREAM_A_CONTROL1 0x81c #define TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT 0x820 #define TEGRA_CSI_PIXEL_STREAM_A_GAP 0x824 #define TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND 0x828 #define TEGRA_CSI_INPUT_STREAM_B_CONTROL 0x83c #define TEGRA_CSI_PIXEL_STREAM_B_CONTROL0 0x844 #define TEGRA_CSI_PIXEL_STREAM_B_CONTROL1 0x848 #define TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT 0x84c #define TEGRA_CSI_PIXEL_STREAM_B_GAP 0x850 #define TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND 0x854 #define TEGRA_CSI_PHY_CIL_COMMAND 0x868 #define TEGRA_CSI_PHY_CILA_CONTROL0 0x86c #define TEGRA_CSI_PHY_CILB_CONTROL0 0x870 #define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x878 #define TEGRA_CSI_CSI_CIL_STATUS 0x87c #define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x880 #define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x884 #define TEGRA_CSI_CSI_READONLY_STATUS 0x888 #define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x88c #define TEGRA_CSI_ESCAPE_MODE_DATA 0x890 #define TEGRA_CSI_CILA_PAD_CONFIG0 0x894 #define TEGRA_CSI_CILA_PAD_CONFIG1 0x898 #define TEGRA_CSI_CILB_PAD_CONFIG0 0x89c #define TEGRA_CSI_CILB_PAD_CONFIG1 0x8a0 #define TEGRA_CSI_CIL_PAD_CONFIG 0x8a4 #define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x8a8 #define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x8ac #define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x8b0 #define TEGRA_CSI_CLKEN_OVERRIDE 0x8b4 #define TEGRA_CSI_DEBUG_CONTROL 0x8b8 #define TEGRA_CSI_DEBUG_COUNTER 0x8bc #define TEGRA_CSI_DEBUG_COUNTER_1 0x8c0 #define TEGRA_CSI_DEBUG_COUNTER_2 0x8c4 #define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x8c8 #define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x8cc #define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x8d0 /* Test Pattern Generator of CSI */ #define TEGRA_CSI_PATTERN_GENERATOR_CTRL_A 0x940 #define TEGRA_CSI_PG_BLANK_A 0x944 #define TEGRA_CSI_PG_PHASE_A 0x948 #define TEGRA_CSI_PG_RED_FREQ_A 0x94c #define TEGRA_CSI_PG_RED_FREQ_RATE_A 0x950 #define TEGRA_CSI_PG_GREEN_FREQ_A 0x954 #define TEGRA_CSI_PG_GREEN_FREQ_RATE_A 0x958 #define TEGRA_CSI_PG_BLUE_FREQ_A 0x95c #define TEGRA_CSI_PG_BLUE_FREQ_RATE_A 0x960 #define TEGRA_CSI_PATTERN_GENERATOR_CTRL_B 0x974 #define TEGRA_CSI_PG_BLANK_B 0x978 #define TEGRA_CSI_PG_PHASE_B 0x97c #define TEGRA_CSI_PG_RED_FREQ_B 0x980 #define TEGRA_CSI_PG_RED_FREQ_RATE_B 0x984 #define TEGRA_CSI_PG_GREEN_FREQ_B 0x988 #define TEGRA_CSI_PG_GREEN_FREQ_RATE_B 0x98c #define TEGRA_CSI_PG_BLUE_FREQ_B 0x990 #define TEGRA_CSI_PG_BLUE_FREQ_RATE_B 0x994 static int vi_port_is_valid(int port) { return (((port) >= TEGRA_CAMERA_PORT_CSI_A) && ((port) <= TEGRA_CAMERA_PORT_VIP)); } static int vi_port_is_csi(int port) { return (((port) == TEGRA_CAMERA_PORT_CSI_A) || ((port) == TEGRA_CAMERA_PORT_CSI_B)); } /* Clock settings for camera */ static struct tegra_camera_clk vi_clks[] = { { .name = "vi", .freq = 150000000, }, { .name = "vi_sensor", .freq = 24000000, }, { .name = "csi", .freq = 0, }, { .name = "isp", .freq = 0, }, { .name = "csus", .freq = 0, }, { .name = "sclk", .freq = 80000000, }, { .name = "emc", .freq = 375000000, }, #ifdef TEGRA_11X_OR_HIGHER_CONFIG { .name = "cilab", .freq = 102000000, }, { .name = "cilcd", .freq = 0, }, { .name = "cile", .freq = 0, }, /* Always put "p11_d2" at the end */ { .name = "pll_d2", .freq = 0, }, #endif }; static int vi_clks_init(struct tegra_camera_dev *cam, int port) { struct platform_device *pdev = cam->ndev; struct tegra_camera_clk *clks; int i; cam->num_clks = ARRAY_SIZE(vi_clks); cam->clks = vi_clks; for (i = 0; i < cam->num_clks; i++) { clks = &cam->clks[i]; clks->clk = devm_clk_get(&pdev->dev, clks->name); if (IS_ERR_OR_NULL(clks->clk)) { clks->clk = NULL; dev_err(&pdev->dev, "Failed to get clock %s.\n", clks->name); return PTR_ERR(clks->clk); } if (clks->freq > 0) clk_set_rate(clks->clk, clks->freq); } return 0; } static void vi_clks_deinit(struct tegra_camera_dev *cam) { /* We don't need cleanup for devm_clk_get() */ return; } static void vi_clks_enable(struct tegra_camera_dev *cam) { struct tegra_camera_clk *clks; int i; for (i = 0; i < cam->num_clks - 1; i++) { clks = &cam->clks[i]; if (clks->clk) clk_prepare_enable(clks->clk); } #ifdef CONFIG_ARCH_TEGRA_2x_SOC #define TEGRA_APB_MISC_BASE 0x70000000 { 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 (cam->tpg_mode) { clks = &cam->clks[i]; if (clks->clk) { clk_prepare_enable(clks->clk); #ifdef TEGRA_11X_OR_HIGHER_CONFIG tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_DSI_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(clks->clk, TEGRA_CLK_VI_INP_SEL, 2); #endif } } } static void vi_clks_disable(struct tegra_camera_dev *cam) { struct tegra_camera_clk *clks; int i; for (i = 0; i < cam->num_clks - 1; i++) { clks = &cam->clks[i]; if (clks->clk) clk_disable_unprepare(clks->clk); } if (cam->tpg_mode) { clks = &cam->clks[i]; if (clks->clk) { #ifdef TEGRA_11X_OR_HIGHER_CONFIG tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 0); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_DSI_OUT_ENB, 0); #endif clk_disable_unprepare(clks->clk); } } } static void vi_init_syncpts(struct tegra_camera_dev *cam) { cam->syncpt_id_csi_a = nvhost_get_syncpt_client_managed("vi_csi_A"); cam->syncpt_id_csi_b = nvhost_get_syncpt_client_managed("vi_csi_B"); cam->syncpt_id_vip = nvhost_get_syncpt_client_managed("vi_vip"); } static void vi_free_syncpts(struct tegra_camera_dev *cam) { nvhost_free_syncpt(cam->syncpt_id_csi_a); nvhost_free_syncpt(cam->syncpt_id_csi_b); nvhost_free_syncpt(cam->syncpt_id_vip); } static void vi_save_syncpts(struct tegra_camera_dev *cam) { u32 val; if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_csi_a, &val)) cam->syncpt_csi_a = val; if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_csi_b, &val)) cam->syncpt_csi_b = val; if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_vip, &val)) cam->syncpt_vip = val; } static void vi_incr_syncpts(struct tegra_camera_dev *cam) { nvhost_syncpt_cpu_incr_ext(cam->ndev, cam->syncpt_id_csi_a); nvhost_syncpt_cpu_incr_ext(cam->ndev, cam->syncpt_id_csi_b); nvhost_syncpt_cpu_incr_ext(cam->ndev, cam->syncpt_id_vip); } static void vi_capture_clean(struct tegra_camera_dev *cam) { TC_VI_REG_WT(cam, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_STATUS, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_READONLY_STATUS, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_ESCAPE_MODE_DATA, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_CONTROL, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_COUNTER, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_COUNTER_1, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_COUNTER_2, 0x0); } static void vi_capture_setup_csi_a(struct tegra_camera_dev *cam, struct soc_camera_device *icd, u32 hdr) { struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILA_CONTROL0, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CILA_PAD_CONFIG0, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CILA_PAD_CONFIG1, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_VI_CORE_CONTROL, 0x02000000); /* CSI-A H_ACTIVE and V_ACTIVE */ TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPA_H_ACTIVE, (icd->user_width << 16)); TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPA_V_ACTIVE, (icd->user_height << 16)); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x1); /* Frame # for top field detect for interlaced */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, bytes_per_line); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00140000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, ((icd->user_height + cam->tpg_mode) << 16)); /* pad 0s enabled, virtual channel ID 00 */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, (0x1 << 16) | /* Output 1 pixel per clock */ (hdr << 8) | /* If hdr shows wrong fmt, use right value */ (0x1 << 7) | /* Check header CRC */ (0x1 << 6) | /* Use word count field in the header */ (0x1 << 5) | /* Look at data identifier byte in hdr */ (0x1 << 4)); /* Expect packet header */ TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_A_CONTROL, (0x3f << 16) | /* Skip packet threshold */ (pdata->lanes - 1)); /* Use 0x00000022 for continuous clock mode. */ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILA_CONTROL0, (pdata->continuous_clk << 5) | 0x5); /* Clock settle time */ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END, (0x1 << 8) | /* Enable continuous syncpt */ cam->syncpt_id_csi_a); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x00020001); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x0000f002); if (cam->tpg_mode) { TC_VI_REG_WT(cam, TEGRA_CSI_PATTERN_GENERATOR_CTRL_A, ((cam->tpg_mode - 1) << 2) | 0x1); TC_VI_REG_WT(cam, TEGRA_CSI_PG_PHASE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_A, 0x00800080); TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_RATE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_A, 0x00800080); TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_RATE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_A, 0x00800080); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_RATE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLANK_A, 0x0000FFFF); } } static void vi_capture_setup_csi_b(struct tegra_camera_dev *cam, struct soc_camera_device *icd, u32 hdr) { struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILB_CONTROL0, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CILB_PAD_CONFIG0, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CILB_PAD_CONFIG1, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x00000000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_VI_CORE_CONTROL, 0x04000000); /* CSI-B H_ACTIVE and V_ACTIVE */ TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPB_H_ACTIVE, (icd->user_width << 16)); TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPB_V_ACTIVE, (icd->user_height << 16)); /* pad 0s enabled, virtual channel ID 00 */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, (0x1 << 16) | /* Output 1 pixel per clock */ (hdr << 8) | /* If hdr shows wrong fmt, use right value */ (0x1 << 7) | /* Check header CRC */ (0x1 << 6) | /* Use word count field in the header */ (0x1 << 5) | /* Look at data identifier byte in hdr */ (0x1 << 4) | /* Expect packet header */ 0x1); /* Set PPB stream source to CSI B */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x1); /* Frame # for top field detect for interlaced */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, bytes_per_line); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00140000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, (icd->user_height << 16) | (0x100 << 4) | /* Wait 0x100 vi clks for timeout */ 0x1); /* Enable line timeout */ TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_B_CONTROL, (0x3f << 16) | /* Skip packet threshold */ (pdata->lanes - 1)); /* Use 0x00000022 for continuous clock mode. */ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILB_CONTROL0, (pdata->continuous_clk << 5) | 0x5); /* Clock settle time */ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END, (0x1 << 8) | /* Enable continuous syncpt */ cam->syncpt_id_csi_b); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x00010002); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x0000f002); } static void vi_capture_setup_vip(struct tegra_camera_dev *cam, struct soc_camera_device *icd, u32 input_control) { TC_VI_REG_WT(cam, TEGRA_VI_VI_CORE_CONTROL, 0x00000000); TC_VI_REG_WT(cam, TEGRA_VI_VI_INPUT_CONTROL, (1 << 27) | /* field detect */ (1 << 25) | /* hsync/vsync decoded from data (BT.656) */ (1 << 1) | /* VIP_INPUT_ENABLE */ input_control); TC_VI_REG_WT(cam, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000); TC_VI_REG_WT(cam, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000); /* VIP H_ACTIVE and V_ACTIVE */ TC_VI_REG_WT(cam, TEGRA_VI_VIP_H_ACTIVE, (icd->user_width << 16) | TEGRA_VIP_H_ACTIVE_START); TC_VI_REG_WT(cam, TEGRA_VI_VIP_V_ACTIVE, (icd->user_height << 16) | TEGRA_VIP_V_ACTIVE_START); /* * For VIP, D9..D2 is mapped to the video decoder's P7..P0. * Disable/mask out the other Dn wires. */ TC_VI_REG_WT(cam, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc); TC_VI_REG_WT(cam, TEGRA_VI_VI_DATA_INPUT_CONTROL, 0x000003fc); TC_VI_REG_WT(cam, TEGRA_VI_PIN_INVERSION, 0x00000000); TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_VIP_VSYNC, (0x1 << 8) | /* Enable continuous syncpt */ cam->syncpt_id_vip); TC_VI_REG_WT(cam, TEGRA_VI_CAMERA_CONTROL, 0x00000004); } static int vi_capture_output_channel_setup( struct tegra_camera_dev *cam, struct soc_camera_device *icd) { struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int port = pdata->port; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); const struct soc_camera_format_xlate *current_fmt = icd->current_fmt; u32 output_fourcc = current_fmt->host_fmt->fourcc; u32 output_format, output_control; struct tegra_camera_buffer *buf = to_tegra_vb(cam->active); switch (output_fourcc) { case V4L2_PIX_FMT_UYVY: output_format = 0x3; /* Default to YUV422 */ break; case V4L2_PIX_FMT_VYUY: output_format = (0x1 << 17) | 0x3; break; case V4L2_PIX_FMT_YUYV: output_format = (0x2 << 17) | 0x3; break; case V4L2_PIX_FMT_YVYU: output_format = (0x3 << 17) | 0x3; break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: output_format = 0x6; /* YUV420 planar */ break; case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SBGGR10: /* Use second output channel for RAW8/RAW10 */ buf->output_channel = 1; if (port == TEGRA_CAMERA_PORT_CSI_A) output_format = 0x7; else if (port == TEGRA_CAMERA_PORT_CSI_B) output_format = 0x8; else output_format = 0x9; break; default: dev_err(&cam->ndev->dev, "Wrong output format %d\n", output_fourcc); return -EINVAL; } output_control = (pdata->flip_v ? (0x1 << 20) : 0) | (pdata->flip_h ? (0x1 << 19) : 0) | output_format; if (buf->output_channel == 0) { TC_VI_REG_WT(cam, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL, output_control); /* * Set up frame size. Bits 31:16 are the number of lines, and * bits 15:0 are the number of pixels per line. */ TC_VI_REG_WT(cam, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE, (icd->user_height << 16) | icd->user_width); /* First output memory enabled */ TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE, 0x00000000); /* Set the number of frames in the buffer. */ TC_VI_REG_WT(cam, TEGRA_VI_VB0_COUNT_FIRST, 0x00000001); /* Set up buffer frame size. */ TC_VI_REG_WT(cam, TEGRA_VI_VB0_SIZE_FIRST, (icd->user_height << 16) | icd->user_width); TC_VI_REG_WT(cam, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST, (icd->user_height * bytes_per_line)); TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_OUT_1, (0x1 << 8) | /* Enable continuous syncpt */ cam->syncpt_id_vip); TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE, 0x00000000); } else if (buf->output_channel == 1) { TC_VI_REG_WT(cam, TEGRA_VI_VI_SECOND_OUTPUT_CONTROL, output_control); TC_VI_REG_WT(cam, TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE, (icd->user_height << 16) | icd->user_width); TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE_2, 0x00000000); /* Set the number of frames in the buffer. */ TC_VI_REG_WT(cam, TEGRA_VI_VB0_COUNT_SECOND, 0x00000001); /* Set up buffer frame size. */ TC_VI_REG_WT(cam, TEGRA_VI_VB0_SIZE_SECOND, (icd->user_height << 16) | icd->user_width); TC_VI_REG_WT(cam, TEGRA_VI_VB0_BUFFER_STRIDE_SECOND, (icd->user_height * bytes_per_line)); TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_OUT_2, (0x1 << 8) | /* Enable continuous syncpt */ cam->syncpt_id_vip); TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE_2, 0x00000000); } else { dev_err(&cam->ndev->dev, "Wrong output channel %d\n", buf->output_channel); return -EINVAL; } return 0; } static int vi_capture_setup(struct tegra_camera_dev *cam, struct tegra_camera_buffer *buf) { 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; const struct soc_camera_format_xlate *current_fmt = icd->current_fmt; enum v4l2_mbus_pixelcode input_code = current_fmt->code; u32 hdr, input_control = 0x0; switch (input_code) { case V4L2_MBUS_FMT_UYVY8_2X8: input_control |= 0x2 << 8; hdr = 30; break; case V4L2_MBUS_FMT_VYUY8_2X8: input_control |= 0x3 << 8; hdr = 30; break; case V4L2_MBUS_FMT_YUYV8_2X8: input_control |= 0x0; hdr = 30; break; case V4L2_MBUS_FMT_YVYU8_2X8: input_control |= 0x1 << 8; hdr = 30; break; case V4L2_MBUS_FMT_SBGGR8_1X8: case V4L2_MBUS_FMT_SGBRG8_1X8: input_control |= 0x2 << 2; /* Input Format = Bayer */ hdr = 42; break; case V4L2_MBUS_FMT_SBGGR10_1X10: input_control |= 0x2 << 2; /* Input Format = Bayer */ hdr = 43; break; default: dev_err(&cam->ndev->dev, "Input format %d is not supported\n", input_code); return -EINVAL; } /* * Set up low pass filter. Use 0x240 for chromaticity and 0x240 * for luminance, which is the default and means not to touch * anything. */ TC_VI_REG_WT(cam, TEGRA_VI_H_LPF_CONTROL, 0x02400240); /* Set up raise-on-edge, so we get an interrupt on end of frame. */ TC_VI_REG_WT(cam, TEGRA_VI_VI_RAISE, 0x00000001); /* Setup registers for CSI-A, CSI-B and VIP inputs */ if (port == TEGRA_CAMERA_PORT_CSI_A) vi_capture_setup_csi_a(cam, icd, hdr); else if (port == TEGRA_CAMERA_PORT_CSI_B) vi_capture_setup_csi_b(cam, icd, hdr); else vi_capture_setup_vip(cam, icd, input_control); /* Setup registers for output channels */ return vi_capture_output_channel_setup(cam, icd); } static int vi_capture_buffer_setup(struct tegra_camera_dev *cam, struct tegra_camera_buffer *buf) { struct soc_camera_device *icd = buf->icd; switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_U, buf->buffer_addr_u); TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_U, buf->start_addr_u); TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_V, buf->buffer_addr_v); TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_V, buf->start_addr_v); case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SBGGR10: case V4L2_PIX_FMT_RGB32: /* output 1 */ if (buf->output_channel == 0) { TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_FIRST, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_FIRST, buf->start_addr); /* output 2 */ } else if (buf->output_channel == 1) { TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_SECOND, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_SECOND, buf->start_addr); } else { dev_err(&cam->ndev->dev, "Wrong output channel %d\n", buf->output_channel); return -EINVAL; } break; default: dev_err(&cam->ndev->dev, "Wrong host format %d\n", icd->current_fmt->host_fmt->fourcc); return -EINVAL; } return 0; } static int vi_capture_start(struct tegra_camera_dev *cam, struct tegra_camera_buffer *buf) { 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; int err; err = vi_capture_buffer_setup(cam, buf); if (err < 0) return err; /* * Only wait on CSI frame end syncpt if we're using CSI. Otherwise, * wait on VIP VSYNC syncpt. */ if (port == TEGRA_CAMERA_PORT_CSI_A) { cam->syncpt_csi_a++; TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x0000f005); err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_a, cam->syncpt_csi_a, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); } else if (port == TEGRA_CAMERA_PORT_CSI_B) { cam->syncpt_csi_b++; TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x0000f005); err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_b, cam->syncpt_csi_b, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); } else { cam->syncpt_vip++; TC_VI_REG_WT(cam, TEGRA_VI_CAMERA_CONTROL, 0x00000001); err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_vip, cam->syncpt_csi_a, TEGRA_SYNCPT_VI_WAIT_TIMEOUT, NULL, NULL); } if (!err) return 0; if (vi_port_is_csi(port)) { u32 ppstatus; u32 cilstatus; u32 rostatus; dev_warn(&icd->vdev->dev, "Timeout on CSI syncpt\n"); dev_warn(&icd->vdev->dev, "buffer_addr = 0x%08x\n", buf->buffer_addr); ppstatus = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); cilstatus = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_STATUS); rostatus = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_READONLY_STATUS); dev_warn(&icd->vdev->dev, "PPSTATUS = 0x%08x, " "CILSTATUS = 0x%08x, " "ROSTATUS = 0x%08x\n", ppstatus, cilstatus, rostatus); } else { u32 vip_input_status; dev_warn(&cam->ndev->dev, "Timeout on VI syncpt\n"); dev_warn(&cam->ndev->dev, "buffer_addr = 0x%08x\n", buf->buffer_addr); vip_input_status = TC_VI_REG_RD(cam, TEGRA_VI_VIP_INPUT_STATUS); dev_warn(&cam->ndev->dev, "VIP_INPUT_STATUS = 0x%08x\n", vip_input_status); } return err; } static int vi_capture_stop(struct tegra_camera_dev *cam, int port) { int err = 0; if (vi_port_is_csi(port)) err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_vip, cam->syncpt_vip, TEGRA_SYNCPT_VI_WAIT_TIMEOUT, NULL, NULL); if (err) { u32 buffer_addr; u32 ppstatus; u32 cilstatus; dev_warn(&cam->ndev->dev, "Timeout on VI syncpt\n"); buffer_addr = TC_VI_REG_RD(cam, TEGRA_VI_VB0_BASE_ADDRESS_FIRST); dev_warn(&cam->ndev->dev, "buffer_addr = 0x%08x\n", buffer_addr); ppstatus = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS); cilstatus = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_STATUS); dev_warn(&cam->ndev->dev, "PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n", ppstatus, cilstatus); } return err; } static void vi_unpowergate(struct tegra_camera_dev *cam) { /* * Powergating DIS must powergate VE partition. Camera * module needs to increase the ref-count of disa to * avoid itself powergated by DIS inadvertently. */ #if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC) tegra_unpowergate_partition(TEGRA_POWERGATE_DISA); #endif } static void vi_powergate(struct tegra_camera_dev *cam) { #if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC) tegra_powergate_partition(TEGRA_POWERGATE_DISA); #endif } struct tegra_camera_ops vi_ops = { .clks_init = vi_clks_init, .clks_deinit = vi_clks_deinit, .clks_enable = vi_clks_enable, .clks_disable = vi_clks_disable, .capture_clean = vi_capture_clean, .capture_setup = vi_capture_setup, .capture_start = vi_capture_start, .capture_stop = vi_capture_stop, .activate = vi_unpowergate, .deactivate = vi_powergate, .init_syncpts = vi_init_syncpts, .free_syncpts = vi_free_syncpts, .save_syncpts = vi_save_syncpts, .incr_syncpts = vi_incr_syncpts, .port_is_valid = vi_port_is_valid, }; int vi_register(struct tegra_camera_dev *cam) { /* Init regulator */ #ifdef CONFIG_ARCH_TEGRA_2x_SOC cam->regulator_name = "vcsi"; #else cam->regulator_name = "avdd_dsi_csi"; #endif /* Init VI/CSI ops */ cam->ops = &vi_ops; return 0; }