camera: add dvp camera [1/1]
authorGuosong Zhou <guosong.zhou@amlogic.com>
Wed, 2 Jan 2019 11:00:30 +0000 (06:00 -0500)
committerJianxin Pan <jianxin.pan@amlogic.com>
Thu, 3 Jan 2019 03:59:37 +0000 (19:59 -0800)
PD#OTT-1204

Problem:
don't support dvp camera

Solution:
add dvp camera gc2145 camera driver

Verify:
test pass on U200

Change-Id: I5927d49a93952587af7bb460a5c405293d692153
Signed-off-by: Guosong Zhou <guosong.zhou@amlogic.com>
25 files changed:
MAINTAINERS
arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts
arch/arm/configs/meson64_a32_defconfig
arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts
arch/arm64/configs/meson64_defconfig
drivers/amlogic/media/Kconfig
drivers/amlogic/media/Makefile
drivers/amlogic/media/camera/Kconfig [new file with mode: 0644]
drivers/amlogic/media/camera/Makefile [new file with mode: 0644]
drivers/amlogic/media/camera/common/cam_prober.c [new file with mode: 0644]
drivers/amlogic/media/camera/common/config_parser.c [new file with mode: 0644]
drivers/amlogic/media/camera/common/config_parser.h [new file with mode: 0644]
drivers/amlogic/media/camera/common/flashlight.c [new file with mode: 0644]
drivers/amlogic/media/camera/common/plat_ctrl.c [new file with mode: 0644]
drivers/amlogic/media/camera/common/plat_ctrl.h [new file with mode: 0644]
drivers/amlogic/media/camera/common/vm.c [new file with mode: 0644]
drivers/amlogic/media/camera/common/vm.h [new file with mode: 0644]
drivers/amlogic/media/camera/common/vm_log.h [new file with mode: 0644]
drivers/amlogic/media/camera/common/vmcls.h [new file with mode: 0644]
drivers/amlogic/media/camera/gc2145.c [new file with mode: 0644]
drivers/amlogic/media/common/canvas/canvas_mgr.c
drivers/amlogic/media/common/vfm/vfm.c
include/linux/amlogic/media/camera/aml_cam_info.h [new file with mode: 0644]
include/linux/amlogic/media/camera/flashlight.h [new file with mode: 0644]
include/linux/amlogic/media/camera/vmapi.h [new file with mode: 0644]

index 4ccdbfe..bc4e9eb 100644 (file)
@@ -14750,3 +14750,16 @@ AMLOGIC MESONAXG RSR DTS
 M:     Yeping Miao <yeping.miao@amlogic.com>
 F:     arch/arm64/boot/dts/amlogic/axg_rsr.dts
 F:     arch/arm64/boot/dts/amlogic/axg_rsr_v03.dts
+
+AMLOGIC CAMERA DRIVER
+M:     Guosong Zhou <guosong.zhou@amlogic.com>
+F:     arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts
+F:     arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts
+F:     arch/arm64/configs/meson64_defconfig
+F:     arch/arm/configs/meson64_a32_defconfig
+F:     drivers/amlogic/media/Kconfig
+F:     drivers/amlogic/media/Makefile
+F:     drivers/amlogic/media/camera/*
+F:     drivers/amlogic/media/common/canvas/canvas_mgr.c
+F:     drivers/amlogic/media/common/vfm/vfm.c
+F:     include/linux/amlogic/media/camera/*
\ No newline at end of file
index 14efeb2..8cf27c5 100644 (file)
                        size = <0x04000000>;
                        alignment = <0x400000>;
                };
+               vm0_cma_reserved:linux,vm0_cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0x0 0x2000000>;
+                       alignment = <0x0 0x400000>;
+               };
        };
 
        gpioleds {
                dev_name = "ionvideo";
                status = "okay";
        };
+       vm0 {
+               compatible = "amlogic, vm";
+               memory-region = <&vm0_cma_reserved>;
+               dev_name = "vm0";
+               status = "disabled";
+               vm_id = <0>;
+       };
+
+       amvdec_656in {
+               /*bt656 gpio conflict with i2c0*/
+               compatible = "amlogic, amvdec_656in";
+               dev_name = "amvdec_656in";
+               status = "disabled";
+               reg = <0x0 0xffe02000 0x0 0x7c>;
+               clocks = <&clkc CLKID_BT656_COMP>,
+                     <&clkc CLKID_BT656>;
+               clock-names = "cts_bt656_clk1",
+                     "clk_gate_bt656";
+               /* bt656in1, bt656in2 */
+               bt656in1 {
+               bt656_id = <1>;
+               status = "disabled";
+               };
+       };
+
+       aml_cams {
+               compatible = "amlogic, cams_prober";
+               status = "disabled";
+               pinctrl-names="default";
+               pinctrl-0=<&cam_dvp_pins &gen_clk_ee_z>;
+               clocks = <&clkc CLKID_GEN_CLK>;
+               clock-names = "g12a_24m";
+               cam_0{
+                       cam_name = "gc2145";
+                       front_back = <0>;
+                       /*u200 i2c2 gpio conflict with ethmac*/
+                       camera-i2c-bus = <&i2c2>;
+                       gpio_pwdn-gpios = <&gpio GPIOZ_2 GPIO_ACTIVE_HIGH>;
+                       gpio_rst-gpios = <&gpio GPIOZ_12 GPIO_ACTIVE_HIGH>;
+                       mirror_flip = <1>;
+                       vertical_flip = <1>;
+                       spread_spectrum = <0>;
+                       bt_path = "gpio";
+                       bt_path_count = <1>;
+                       vdin_path = <0>;
+                       status = "okay";
+               };
+       };
 
        gpio_keypad{
                compatible = "amlogic, gpio_keypad";
        };
 };
 
+&i2c2 {
+       status = "disabled";
+       pinctrl-names="default";
+       pinctrl-0=<&i2c2_master_pins2>;
+       clock-frequency = <100000>;
+};
+
 &i2c3 {
        status = "okay";
        pinctrl-names="default";
                };
        };
 
+       clk12_24_z_pins:clk12_24_z_pins {
+               mux {
+                       groups = "clk12_24_z";
+                       function = "clk12_24_ee";
+                       drive-strength = <3>;
+               };
+       };
+
+       gen_clk_ee_z: gen_clk_ee_z {
+               mux {
+                       groups="gen_clk_ee_z";
+                       function="gen_clk_ee";
+                       drive-strength = <3>;
+               };
+       };
+
+       cam_dvp_pins:cam_dvp_pins {
+               mux {
+                       groups = "bt656_a_vs", "bt656_a_hs", "bt656_a_clk",
+                               "bt656_a_din0", "bt656_a_din1", "bt656_a_din2",
+                               "bt656_a_din3", "bt656_a_din4", "bt656_a_din5",
+                               "bt656_a_din6", "bt656_a_din7";
+                       function = "bt656";
+               };
+       };
+
 
 }; /* end of pinctrl_periphs */
 &pinctrl_aobus {
index 71f5e9f..9cb58f8 100644 (file)
@@ -325,6 +325,9 @@ CONFIG_AMLOGIC_MEDIA_ENHANCEMENT=y
 CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM=y
 CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION=y
 CONFIG_AMLOGIC_MEDIA_GDC=y
+CONFIG_AMLOGIC_VIDEO_CAPTURE=y
+CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER=y
+CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145=y
 CONFIG_AMLOGIC_DTV_DEMOD=y
 CONFIG_AMLOGIC_MMC=y
 CONFIG_AMLOGIC_NAND=y
index 4ece6da..1a8d55d 100644 (file)
                        size = <0x0 0x04000000>;
                        alignment = <0x0 0x400000>;
                };
+               vm0_cma_reserved:linux,vm0_cma {
+                       compatible = "shared-dma-pool";
+                       reusable;
+                       size = <0x0 0x2000000>;
+                       alignment = <0x0 0x400000>;
+               };
        };
 
        gpioleds {
                dev_name = "ionvideo";
                status = "okay";
        };
+       vm0 {
+               compatible = "amlogic, vm";
+               memory-region = <&vm0_cma_reserved>;
+               dev_name = "vm0";
+               status = "disabled";
+               vm_id = <0>;
+       };
+
+       amvdec_656in {
+               /*bt656 gpio conflict with i2c0*/
+               compatible = "amlogic, amvdec_656in";
+               dev_name = "amvdec_656in";
+               status = "disabled";
+               reg = <0x0 0xffe02000 0x0 0x7c>;
+               clocks = <&clkc CLKID_BT656_COMP>,
+                     <&clkc CLKID_BT656>;
+               clock-names = "cts_bt656_clk1",
+                     "clk_gate_bt656";
+               /* bt656in1, bt656in2 */
+               bt656in1 {
+               bt656_id = <1>;
+               status = "disabled";
+               };
+       };
+
+       aml_cams {
+               compatible = "amlogic, cams_prober";
+               status = "disabled";
+               pinctrl-names="default";
+               pinctrl-0=<&cam_dvp_pins &gen_clk_ee_z>;
+               clocks = <&clkc CLKID_GEN_CLK>;
+               clock-names = "g12a_24m";
+               cam_0{
+                       cam_name = "gc2145";
+                       front_back = <0>;
+                       /*u200 i2c2 gpio conflict with ethmac*/
+                       camera-i2c-bus = <&i2c2>;
+                       gpio_pwdn-gpios = <&gpio GPIOZ_2 GPIO_ACTIVE_HIGH>;
+                       gpio_rst-gpios = <&gpio GPIOZ_12 GPIO_ACTIVE_HIGH>;
+                       mirror_flip = <1>;
+                       vertical_flip = <1>;
+                       spread_spectrum = <0>;
+                       bt_path = "gpio";
+                       bt_path_count = <1>;
+                       vdin_path = <0>;
+                       status = "okay";
+               };
+       };
 
        gpio_keypad{
                compatible = "amlogic, gpio_keypad";
        };
 };
 
+&i2c2 {
+       status = "disabled";
+       pinctrl-names="default";
+       pinctrl-0=<&i2c2_master_pins2>;
+       clock-frequency = <100000>;
+};
+
 &i2c3 {
        status = "okay";
        pinctrl-names="default";
                };
        };
 
+       clk12_24_z_pins:clk12_24_z_pins {
+               mux {
+                       groups = "clk12_24_z";
+                       function = "clk12_24_ee";
+                       drive-strength = <3>;
+               };
+       };
+
+       gen_clk_ee_z: gen_clk_ee_z {
+               mux {
+                       groups="gen_clk_ee_z";
+                       function="gen_clk_ee";
+                       drive-strength = <3>;
+               };
+       };
+
+       cam_dvp_pins:cam_dvp_pins {
+               mux {
+                       groups = "bt656_a_vs", "bt656_a_hs", "bt656_a_clk",
+                               "bt656_a_din0", "bt656_a_din1", "bt656_a_din2",
+                               "bt656_a_din3", "bt656_a_din4", "bt656_a_din5",
+                               "bt656_a_din6", "bt656_a_din7";
+                       function = "bt656";
+               };
+       };
+
 
 }; /* end of pinctrl_periphs */
 &pinctrl_aobus {
index 45a3aba..7971d54 100644 (file)
@@ -322,6 +322,9 @@ CONFIG_AMLOGIC_MEDIA_ENHANCEMENT=y
 CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM=y
 CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION=y
 CONFIG_AMLOGIC_MEDIA_GDC=y
+CONFIG_AMLOGIC_VIDEO_CAPTURE=y
+CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER=y
+CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145=y
 CONFIG_AMLOGIC_DTV_DEMOD=y
 CONFIG_AMLOGIC_MMC=y
 CONFIG_AMLOGIC_NAND=y
index bc31627..ded82c0 100644 (file)
@@ -94,6 +94,7 @@ source "drivers/amlogic/media/video_processor/Kconfig"
 source "drivers/amlogic/media/enhancement/Kconfig"
 source "drivers/amlogic/media/gdc/Kconfig"
 source "drivers/amlogic/media/algorithm/Kconfig"
+source "drivers/amlogic/media/camera/Kconfig"
 endif
 source "drivers/amlogic/media/dtv_demod/Kconfig"
 endmenu
index dfb7316..12f643b 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_AMLOGIC_DTV_DEMOD) += dtv_demod/
 obj-$(CONFIG_AMLOGIC_MEDIA_GDC) += gdc/
 
 obj-$(CONFIG_AMLOGIC_MEDIA_ALGORITHM) += algorithm/
+obj-$(CONFIG_AMLOGIC_VIDEO_CAPTURE) += camera/
\ No newline at end of file
diff --git a/drivers/amlogic/media/camera/Kconfig b/drivers/amlogic/media/camera/Kconfig
new file mode 100644 (file)
index 0000000..41d08be
--- /dev/null
@@ -0,0 +1,559 @@
+menu "Amlogic Camera Support"
+
+config AMLOGIC_VIDEO_CAPTURE
+       tristate "Amlogic Platform Capture Driver"
+       depends on !SPARC32 && !SPARC64 &&!AMLOGIC_CAMERA_ENABLE
+       select VIDEOBUF_VMALLOC
+       depends on MEDIA_SUPPORT
+       select VIDEO_DEV
+       select VIDEO_V4L2
+       default n
+       ---help---
+         Amlogic capture driver interface in v4l style.
+         it can not work well together with
+         AMLOGIC_CAMERA_ENABLE
+         Say Y here if you want this driver.
+
+config AMLOGIC_CAPTURE_FRAME_ROTATE
+       bool "Enable function to support frame rotation"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       default n
+       ---help---
+         It will support frame rotation when enable this config
+         It will support frame rotation when enable this config
+         It will support frame rotation when enable this config
+         It will support frame rotation when enable this config
+
+config AMLOGIC_VM_DISABLE_VIDEOLAYER
+       bool "Force disable Videolayer when use vm"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       default n
+       ---help---
+    It will disable amvideo provider when enable this config
+    It will disable amvideo provider when enable this config
+    It will disable amvideo provider when enable this config
+    It will disable amvideo provider when enable this config
+
+config AMLOGIC_VIDEO_CAPTURE_PROBE
+       bool "Force check whether camera devices exist"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       default n
+       ---help---
+         Probe whether the camera devices exist by trying to read its
+         i2c port. It may cost some time, say Y here if you want it.
+         Probe whether the camera devices exist by trying to read its
+         i2c port. It may cost some time, say Y here if you want it.
+
+config AMLCAP_LOG_TIME_USEFORFRAMES
+       bool "Print Out The Time(ms) For Process A Frame"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       default n
+       ---help---
+         Print out the time used for process a frame, only for developers.
+         Print out the time used for process a frame, only for developers.
+         Print out the time used for process a frame, only for developers.
+         Print out the time used for process a frame, only for developers.
+
+config AMLOGIC_VIDEO_CAPTURE_GT2005
+       tristate "Amlogic Platform Capture Driver for GT2005"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC0307
+       tristate "Amlogic Platform Capture Driver for GC0307"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC0308
+       tristate "Amlogic Platform Capture Driver for GC0308"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC0328
+       tristate "Amlogic Platform Capture Driver for GC0328"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN_BT656IN
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC0329
+       tristate "Amlogic Platform Capture Driver for GC0329"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC2015
+       tristate "Amlogic Platform Capture Driver for GC2015"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC2035
+       tristate "Amlogic Platform Capture Driver for GC2035"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC2155
+       tristate "Amlogic Platform Capture Driver for GC2155"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_GC2145
+       tristate "Amlogic Platform Capture Driver for GC2145"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_OV5640
+       tristate "Amlogic Platform Capture Driver for OV5640"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_OV5642
+       tristate "Amlogic Platform Capture Driver for OV5642"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+choice
+       prompt "OV5642 AUTO FOCUS FIRMWARE"
+       depends on AMLOGIC_VIDEO_CAPTURE_OV5642
+       default NO_AUTO_FUCOS
+
+config NO_AUTO_FUCOS
+       bool "NONE"
+       ---help---
+         no auto focus
+         no auto focus
+         no auto focus
+         no auto focus
+
+config AD5820
+       bool "AD5820"
+       ---help---
+         AD5820
+         AD5820
+         AD5820
+         AD5820
+
+config DW9714
+       bool "DW9714"
+       ---help---
+         DW9714
+         DW9714
+         DW9714
+         DW9714
+
+config AP5120
+       bool "AP5120"
+       ---help---
+         AP5120
+         AP5120
+         AP5120
+         AP5120
+
+endchoice
+
+config AMLOGIC_VIDEO_CAPTURE_OV7675
+       tristate "Amlogic Platform Capture Driver for OV7675"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_OV2655
+       tristate "Amlogic Platform Capture Driver for OV2655"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_SP0838
+       tristate "Amlogic Platform Capture Driver for SP0838"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select VIDEOBUF_RESOURCE
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_SP2518
+       tristate "Amlogic Platform Capture Driver for SP2518"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select VIDEOBUF_RESOURCE
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_SP0A19
+       tristate "Amlogic Platform Capture Driver for SP0A19"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_SP1628
+       tristate "Amlogic Platform Capture Driver for SP1628"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_HI253
+       tristate "Amlogic Platform Capture Driver for HI253"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_HI704
+       tristate "Amlogic Platform Capture Driver for HI704"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_HM2057
+       tristate "Amlogic Platform Capture Driver for HM2057"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_HM5065
+       tristate "Amlogic Platform Capture Driver for HM5065"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_HM1375
+       tristate "Amlogic Platform Capture Driver for HM1375"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_OV3660
+       tristate "Amlogic Platform Capture Driver for OV3660"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_OV5647
+       tristate "Amlogic Platform Capture Driver for OV5647"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+
+config AMLOGIC_VIDEO_CAPTURE_HI2056
+       tristate "Amlogic Platform Capture Driver for HI2056"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_MIPI
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_NT99250
+       tristate "Amlogic Platform Capture Driver for NT99250"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_NT99252
+       tristate "Amlogic Platform Capture Driver for NT99252"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_NT99340
+       tristate "Amlogic Platform Capture Driver for NT99340"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_AR0543
+       tristate "Amlogic Platform Capture Driver for AR0543"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEO_CAPTURE_AR0833
+       tristate "Amlogic Platform Capture Driver for AR0833"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+
+config AMLOGIC_VIDEO_CAPTURE_BF3720
+       tristate "Amlogic Platform Capture Driver for BF3720"
+       depends on AMLOGIC_VIDEO_CAPTURE
+       select VIDEOBUF_VMALLOC
+       select AMLOGIC_VIDEOIN_MANAGER
+       select TVIN
+       select TVIN_BT656
+       select TVIN_VDIN
+       default n
+       ---help---
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+         Amlogic capture driver.
+         Say Y here if you want this driver.
+
+config AMLOGIC_VIDEOIN_MANAGER
+       tristate "amlogic video manager"
+       default n
+       ---help---
+         this a test for video manager
+
+endmenu
diff --git a/drivers/amlogic/media/camera/Makefile b/drivers/amlogic/media/camera/Makefile
new file mode 100644 (file)
index 0000000..04fb18c
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Makefile for the amlogic platform camera interface device drivers.
+#
+amlflash-objs := common/flashlight.o
+amlcamera-objs := common/plat_ctrl.o
+#common/util.o
+amlvm-objs := common/vm.o
+cam_prober-objs := common/cam_prober.o common/config_parser.o
+gc2145dri-objs := gc2145.o
+
+obj-y  += amlflash.o
+obj-y  += amlvm.o
+obj-y  += amlcamera.o
+obj-y  += cam_prober.o
+obj-$(CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145) += gc2145dri.o
diff --git a/drivers/amlogic/media/camera/common/cam_prober.c b/drivers/amlogic/media/camera/common/cam_prober.c
new file mode 100644 (file)
index 0000000..98fe531
--- /dev/null
@@ -0,0 +1,1792 @@
+/*
+ * drivers/amlogic/media/camera/common/cam_prober.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/delay.h>
+#include <linux/amlogic/media/frame_provider/tvin/tvin.h>
+#include <linux/amlogic/media/camera/aml_cam_info.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/amlogic/iomap.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/media/old_cpu_version.h>
+#include <linux/clk.h>
+
+#define CONFIG_ARCH_MESON8
+
+static struct platform_device *cam_pdev;
+static struct clk *cam_clk;
+static unsigned int bt_path_count;
+
+static unsigned int camera0_pwdn_pin;
+static unsigned int camera0_rst_pin;
+static unsigned int camera1_pwdn_pin;
+static unsigned int camera1_rst_pin;
+
+static struct aml_cam_info_s *temp_cam;
+
+static int aml_camera_read_buff(struct i2c_adapter *adapter,
+                               unsigned short dev_addr, char *buf,
+                               int addr_len, int data_len)
+{
+       int i2c_flag = -1;
+       struct i2c_msg msgs[] = {{
+                       .addr = dev_addr, .flags = 0,
+                   .len = addr_len, .buf = buf,
+               }, {
+                       .addr = dev_addr, .flags = I2C_M_RD,
+                   .len = data_len, .buf = buf,
+               }
+       };
+
+       i2c_flag = i2c_transfer(adapter, msgs, 2);
+
+       return i2c_flag;
+}
+
+static int aml_camera_write_buff(struct i2c_adapter *adapter,
+                                unsigned short dev_addr, char *buf, int len)
+{
+       struct i2c_msg msg[] = {{
+                       .addr = dev_addr, .flags = 0,    /*I2C_M_TEN*/
+                       .len = len, .buf = buf,
+               }
+       };
+
+       if (i2c_transfer(adapter, msg, 1) < 0)
+               return -1;
+       else
+               return 0;
+}
+
+static int aml_i2c_get_byte(struct i2c_adapter *adapter,
+                           unsigned short dev_addr, unsigned short addr)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+
+       if (aml_camera_read_buff(adapter, dev_addr, buff, 2, 1) < 0)
+               return -1;
+       return buff[0];
+}
+
+static int aml_i2c_put_byte(struct i2c_adapter *adapter,
+                           unsigned short dev_addr, unsigned short addr,
+                           unsigned char data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       buff[2] = data;
+       if (aml_camera_write_buff(adapter, dev_addr, buff, 3) < 0)
+               return -1;
+       return 0;
+}
+
+static int aml_i2c_get_byte_add8(struct i2c_adapter *adapter,
+                                unsigned short dev_addr,
+                                unsigned short addr)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)(addr & 0xff);
+
+       if (aml_camera_read_buff(adapter, dev_addr, buff, 1, 1) < 0)
+               return -1;
+       return buff[0];
+}
+
+static int aml_i2c_put_byte_add8(struct i2c_adapter *adapter,
+                                unsigned short dev_addr,
+                                unsigned short addr, unsigned char data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)(addr & 0xff);
+       buff[1] = data;
+       if (aml_camera_write_buff(adapter, dev_addr, buff, 2) < 0)
+               return -1;
+       return 0;
+}
+
+int aml_i2c_put_word(struct i2c_adapter *adapter, unsigned short dev_addr,
+                    unsigned short addr, unsigned short data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       buff[2] = (unsigned char)((data >> 8) & 0xff);
+       buff[3] = (unsigned char)(data & 0xff);
+       if (aml_camera_write_buff(adapter, dev_addr, buff, 4) < 0)
+               return -1;
+       return 0;
+}
+
+static int aml_i2c_get_word(struct i2c_adapter *adapter,
+                           unsigned short dev_addr, unsigned short addr)
+{
+       int ret;
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       if (aml_camera_read_buff(adapter, dev_addr, buff, 2, 2) < 0)
+               return -1;
+       ret = (buff[0] << 8) | (buff[1]);
+       return ret;
+}
+
+static int aml_i2c_get_word_add8(struct i2c_adapter *adapter,
+                                unsigned short dev_addr,
+                                unsigned short addr)
+{
+       int ret;
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       if (aml_camera_read_buff(adapter, dev_addr, buff, 2, 2) < 0)
+               return -1;
+       ret = buff[0] | (buff[1] << 8);
+       return ret;
+}
+
+static int aml_i2c_put_word_add8(struct i2c_adapter *adapter,
+                                unsigned short dev_addr, unsigned char addr,
+                                unsigned short data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)(addr & 0xff);
+       buff[1] = (unsigned char)(data >> 8 & 0xff);
+       buff[2] = (unsigned char)(data & 0xff);
+       if (aml_camera_write_buff(adapter, dev_addr, buff, 3) < 0)
+               return -1;
+       return 0;
+}
+
+
+extern struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0307
+int gc0307_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x21, 0x00);
+       if (reg == 0x99)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0308
+int gc0308_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x21, 0x00);
+       if (reg == 0x9b)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0328
+int gc0328_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x21, 0xf0);
+       if (reg == 0x9d)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0329
+int gc0329_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       aml_i2c_put_byte_add8(adapter, 0x31, 0xfc, 0x16); /*select page 0*/
+       reg = aml_i2c_get_byte_add8(adapter, 0x31, 0x00);
+       if (reg == 0xc0)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2015
+int gc2015_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x30, 0x00);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x30, 0x01);
+       if (reg[0] == 0x20 && reg[1] == 0x05)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM2057
+int hm2057_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x24, 0x0001);
+       reg[1] = aml_i2c_get_byte(adapter, 0x24, 0x0002);
+       if (reg[0] == 0x20 && reg[1] == 0x56)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2035
+int gc2035_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf0);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf1);
+       if (reg[0] == 0x20 && reg[1] == 0x35)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2155
+int gc2155_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf0);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf1);
+       if (reg[0] == 0x21 && reg[1] == 0x55)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GT2005
+int gt2005_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x0000);
+       reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x0001);
+       if (reg[0] == 0x51 && reg[1] == 0x38)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV2659
+int ov2659_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x30, 0x300a);
+       reg[1] = aml_i2c_get_byte(adapter, 0x30, 0x300b);
+       if (reg[0] == 0x26 && reg[1] == 0x56)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3640
+int ov3640_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a);
+       reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b);
+       if (reg[0] == 0x36 && reg[1] == 0x4c)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3660
+int ov3660_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a);
+       reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b);
+       if (reg[0] == 0x36 && reg[1] == 0x60)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640
+int ov5640_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a);
+       reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b);
+       if (reg[0] == 0x56 && reg[1] == 0x40)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5642
+int ov5642_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x3c, 0x300a);
+       reg[1] = aml_i2c_get_byte(adapter, 0x3c, 0x300b);
+       if (reg[0] == 0x56 && reg[1] == 0x42)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV7675
+int ov7675_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x21, 0x0a);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x21, 0x0b);
+       if (reg[0] == 0x76 && reg[1] == 0x73)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0A19
+int sp0a19_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x21, 0x02);
+       if (reg == 0xa6)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP2518
+int sp2518_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x30, 0x02);
+       pr_info("sp2518 chip id reg = %x .\n", reg);
+       if (reg == 0x53)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0838
+int sp0838_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x18, 0x02);
+       if (reg == 0x27)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI253
+int hi253_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg;
+
+       reg = aml_i2c_get_byte_add8(adapter, 0x20, 0x04);
+       if (reg == 0x92)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM5065
+int hm5065_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x1F, 0x0000);
+       reg[1] = aml_i2c_get_byte(adapter, 0x1F, 0x0001);
+       if (reg[0] == 0x03 && reg[1] == 0x9e)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM1375
+int hm1375_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x24, 0x0001);
+       reg[1] = aml_i2c_get_byte(adapter, 0x24, 0x0002);
+       pr_info("hm1375_v4l2_probe: device ID: 0x%x%x", reg[0], reg[1]);
+       if ((reg[0] == 0x13 || reg[0] == 0x03) && reg[1] == 0x75)
+               ret = 1;
+       ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI2056
+int hi2056_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x24, 0x0001);
+       reg[1] = aml_i2c_get_byte(adapter, 0x24, 0x0002);
+       pr_info("reg[0]=%x, reg[1]=%x\n", reg[0], reg[1]);
+       if (reg[0] == 0x20 && reg[1] == 0x56)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5647
+int ov5647_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte(adapter, 0x36, 0x300a);
+       reg[1] = aml_i2c_get_byte(adapter, 0x36, 0x300b);
+       pr_info("reg[0]:%x,reg[1]:%x\n", reg[0], reg[1]);
+       if (reg[0] == 0x56 && reg[1] == 0x47)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0543
+int ar0543_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0, reg_val;
+
+       reg_val = aml_i2c_get_word(adapter, 0x36, 0x3000);
+       pr_info("reg:0x%x\n", reg_val);
+       if (reg_val == 0x4800)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0833
+int ar0833_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0, reg_val;
+
+       reg_val = aml_i2c_get_word(adapter, 0x36, 0x3000);
+       pr_info("reg:0x%x\n", reg_val);
+       if (reg_val == 0x4B03)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP1628
+int sp1628_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0x02);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xa0);
+       if (reg[0] == 0x16 && reg[1] == 0x28)
+               ret = 1;
+       return ret;
+}
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3720
+int bf3720_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfc);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfd);
+       if (reg[0] == 0x37 && reg[1] == 0x20)
+               ret = 1;
+       return ret;
+}
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3703
+int __init bf3703_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfc); /*i2c addr:0x6f*/
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfd);
+       if (reg[0] == 0x37 && reg[1] == 0x03)
+               ret = 1;
+       return ret;
+}
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3920
+int __init bf3920_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfc); /*i2c addr:0x6f*/
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x6e, 0xfd);
+       if (reg[0] == 0x39 && reg[1] == 0x20)
+               ret = 1;
+       return ret;
+}
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145
+int __init gc2145_v4l2_probe(struct i2c_adapter *adapter)
+{
+       int ret = 0;
+       unsigned char reg[2];
+
+       reg[0] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf0);
+       reg[1] = aml_i2c_get_byte_add8(adapter, 0x3c, 0xf1);
+       /*datasheet chip id is error*/
+       if (reg[0] == 0x21 && reg[1] == 0x45)
+               ret = 1;
+       pr_info("%s, ret = %d\n", __func__, ret);
+       return ret;
+}
+#endif
+
+struct aml_cam_dev_info_s {
+       unsigned char addr;
+       char *name;
+       unsigned char pwdn;
+       enum resolution_size max_cap_size;
+       aml_cam_probe_fun_t probe_func;
+};
+
+static const struct aml_cam_dev_info_s cam_devs[] = {
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0307
+       {
+               .addr = 0x21,
+               .name = "gc0307",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = gc0307_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0308
+       {
+               .addr = 0x21,
+               .name = "gc0308",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = gc0308_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0328
+       {
+               .addr = 0x21,
+               .name = "gc0328",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = gc0328_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC0329
+       {
+               .addr = 0x31,
+               .name = "gc0329",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = gc0329_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2015
+       {
+               .addr = 0x30,
+               .name = "gc2015",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = gc2015_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM2057
+       {
+               .addr = 0x24,
+               .name = "hm2057",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = hm2057_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2035
+       {
+               .addr = 0x3c,
+               .name = "gc2035",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = gc2035_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2155
+       {
+               .addr = 0x3c,
+               .name = "gc2155",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = gc2155_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GT2005
+       {
+               .addr = 0x3c,
+               .name = "gt2005",
+               .pwdn = 0,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = gt2005_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV2659
+       {
+               .addr = 0x30,
+               .name = "ov2659",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = ov2659_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3640
+       {
+               .addr = 0x3c,
+               .name = "ov3640",
+               .pwdn = 1,
+               .max_cap_size = SIZE_2048X1536;
+               .probe_func = ov3640_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV3660
+       {
+               .addr = 0x3c,
+               .name = "ov3660",
+               .pwdn = 1,
+               .max_cap_size = SIZE_2048X1536,
+               .probe_func = ov3660_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5640
+       {
+               .addr = 0x3c,
+               .name = "ov5640",
+               .pwdn = 1,
+               .max_cap_size = SIZE_2592X1944,
+               .probe_func = ov5640_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5642
+       {
+               .addr = 0x3c,
+               .name = "ov5642",
+               .pwdn = 1,
+               .max_cap_size = SIZE_2592X1944,
+               .probe_func = ov5642_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV5647
+       {
+               .addr = 0x36, /* really value should be 0x6c  */
+               .name = "ov5647", .pwdn = 1, .max_cap_size = SIZE_2592X1944,
+               .probe_func = ov5647_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_OV7675
+       {
+               .addr = 0x21,
+               .name = "ov7675",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = ov7675_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0A19
+       {
+               .addr = 0x21,
+               .name = "sp0a19",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = sp0a19_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP0838
+       {
+               .addr = 0x18,
+               .name = "sp0838",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = sp0838_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP2518
+       {
+               .addr = 0x30,
+               .name = "sp2518",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = sp2518_v4l2_probe,
+       },
+#endif
+
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI253
+       {
+               .addr = 0x20,
+               .name = "hi253",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = hi253_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM5065
+       {
+               .addr = 0x1f,
+               .name = "hm5065",
+               .pwdn = 0,
+               .max_cap_size = SIZE_2592X1944,
+               .probe_func = hm5065_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HM1375
+       {
+               .addr = 0x24,
+               .name = "hm1375",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1280X1024,
+               .probe_func = hm1375_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_HI2056
+       {
+               .addr = 0x24,
+               .name = "mipi-hi2056",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = hi2056_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0543
+       {
+               .addr = 0x36,
+               .name = "ar0543",
+               .pwdn = 0,
+               .max_cap_size = SIZE_2592X1944,
+               .probe_func = ar0543_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_AR0833
+       {
+               .addr = 0x36,
+               .name = "ar0833",
+               .pwdn = 0,
+               .max_cap_size = SIZE_2592X1944,
+               .probe_func = ar0833_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_SP1628
+       {
+               .addr = 0x3c,
+               .name = "sp1628",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1280X960,
+               .probe_func = sp1628_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3720
+       {
+               .addr = 0x6e,
+               .name = "bf3720",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = bf3720_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3703
+       {
+               .addr = 0x6e,
+               .name = "bf3703",
+               .pwdn = 1,
+               .max_cap_size = SIZE_640X480,
+               .probe_func = bf3703_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_BF3920
+       {
+               .addr = 0x6e,
+               .name = "bf3920",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = bf3920_v4l2_probe,
+       },
+#endif
+#ifdef CONFIG_AMLOGIC_VIDEO_CAPTURE_GC2145
+       {
+               .addr = 0x3c,
+               .name = "gc2145",
+               .pwdn = 1,
+               .max_cap_size = SIZE_1600X1200,
+               .probe_func = gc2145_v4l2_probe,
+       },
+#endif
+};
+
+static const struct aml_cam_dev_info_s *get_cam_info_by_name(const char *name)
+{
+       int i;
+
+       if (!name)
+               return NULL;
+       /*pr_info("cam_devs num is %d\n", ARRAY_SIZE(cam_devs));*/
+       for (i = 0; i < ARRAY_SIZE(cam_devs); i++) {
+               if (!strcmp(name, cam_devs[i].name)) {
+                       pr_info("camera dev %s found\n", cam_devs[i].name);
+                       pr_info("camera i2c addr: 0x%x\n", cam_devs[i].addr);
+                       return &cam_devs[i];
+               }
+       }
+       return NULL;
+}
+
+struct res_item {
+       enum resolution_size size;
+       char *name;
+};
+
+static const struct res_item res_item_array[] = {
+       {SIZE_320X240, "320X240"}, {
+               SIZE_640X480, "640X480"
+       }, {SIZE_720X405, "720X405"}, {
+               SIZE_800X600, "800X600"
+       }, {SIZE_960X540, "960X540"}, {
+               SIZE_1024X576, "1024X576"
+       }, {SIZE_960X720, "960X720"}, {
+               SIZE_1024X768, "1024X768"
+       }, {SIZE_1280X720, "1280X720"}, {
+               SIZE_1152X864, "1152X864"
+       }, {SIZE_1366X768, "1366X768"}, {
+               SIZE_1280X960, "1280X960"
+       }, {SIZE_1280X1024, "1280X1024"}, {
+               SIZE_1400X1050, "1400X1050"
+       }, {SIZE_1600X900, "1600X900"}, {
+               SIZE_1600X1200, "1600X1200"
+       }, {SIZE_1920X1080, "1920X1080"}, {
+               SIZE_1792X1344, "1792X1344"
+       }, {SIZE_2048X1152, "2048X1152"}, {
+               SIZE_2048X1536, "2048X1536"
+       }, {SIZE_2304X1728, "2304X1728"}, {
+               SIZE_2560X1440, "2560X1440"
+       }, {SIZE_2592X1944, "2592X1944"}, {
+               SIZE_3072X1728, "3072X1728"
+       }, {SIZE_2816X2112, "2816X2112"}, {
+               SIZE_3072X2304, "3072X2304"
+       }, {SIZE_3200X2400, "3200X2400"}, {
+               SIZE_3264X2448, "3264X2448"
+       }, {SIZE_3840X2160, "3840X2160"}, {
+               SIZE_3456X2592, "3456X2592"
+       }, {SIZE_3600X2700, "3600X2700"}, {
+               SIZE_4096X2304, "4096X2304"
+       }, {SIZE_3672X2754, "3672X2754"}, {
+               SIZE_3840X2880, "3840X2880"
+       }, {SIZE_4000X3000, "4000X3000"}, {
+               SIZE_4608X2592, "4608X2592"
+       }, {SIZE_4096X3072, "4096X3072"}, {
+               SIZE_4800X3200, "4800X3200"
+       }, {SIZE_5120X2880, "5120X2880"}, {
+               SIZE_5120X3840, "5120X3840"
+       }, {SIZE_6400X4800, "6400X480"},
+
+};
+
+static enum resolution_size get_res_size(const char *res_str)
+{
+       enum resolution_size ret = SIZE_NULL;
+       const struct res_item *item;
+       int i;
+
+       if (!res_str)
+               return SIZE_NULL;
+       for (i = 0; i < ARRAY_SIZE(res_item_array); i++) {
+               item = &res_item_array[i];
+               if (!strcmp(item->name, res_str)) {
+                       ret = item->size;
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static inline void GXBB_cam_enable_clk(void)
+{
+       struct clk *clk;
+
+       clk = clk_get(&cam_pdev->dev, "clk_camera_24");
+       if (IS_ERR(clk)) {
+               pr_info("cannot get camera m-clock\n");
+               clk = NULL;
+       } else {
+               cam_clk = clk;
+               clk_prepare_enable(clk);
+       }
+}
+
+static inline void GXBB_cam_disable_clk(int spread_spectrum)
+{
+       if (cam_clk) {
+               clk_disable_unprepare(cam_clk);
+               clk_put(cam_clk);
+       }
+}
+
+static inline void GX12_cam_enable_clk(void)
+{
+       struct clk *clk;
+       unsigned long clk_rate;
+
+       clk = devm_clk_get(&cam_pdev->dev, "g12a_24m");
+       if (IS_ERR(clk)) {
+               pr_info("cannot get camera m-clock\n");
+               clk = NULL;
+       } else {
+               cam_clk = clk;
+               clk_set_rate(clk, 24000000);
+               clk_prepare_enable(clk);
+               clk_rate = clk_get_rate(clk);
+       }
+}
+
+static inline void GX12_cam_disable_clk(int spread_spectrum)
+{
+       if (cam_clk) {
+               clk_disable_unprepare(cam_clk);
+               devm_clk_put(&cam_pdev->dev, cam_clk);
+               pr_info("Success disable mclk\n");
+       }
+}
+
+static inline void cam_enable_clk(int clk, int spread_spectrum)
+{
+       pr_err("camera mclk enable failed, unsupport chip\n");
+}
+
+static inline void cam_disable_clk(int spread_spectrum)
+{
+       pr_err("camera mclk disable failed, unsupport chip\n");
+}
+
+/*static struct platform_device *cam_pdev;*/
+
+void aml_cam_init(struct aml_cam_info_s *cam_dev)
+{
+       /*select XTAL as camera clock*/
+       if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB)
+               GXBB_cam_enable_clk();
+       else if ((get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) ||
+               (get_cpu_type() == MESON_CPU_MAJOR_ID_G12B))
+               GX12_cam_enable_clk();
+       else
+               cam_enable_clk(cam_dev->mclk, cam_dev->spread_spectrum);
+
+       /*coding style need: msleep < 20ms can sleep for up to 20ms*/
+       msleep(20);
+       /*set camera power enable*/
+       if (!cam_dev->front_back) {
+               cam_dev->pwdn_pin = camera0_pwdn_pin;
+               cam_dev->rst_pin = camera0_rst_pin;
+       } else {
+               cam_dev->pwdn_pin = camera1_pwdn_pin;
+               cam_dev->rst_pin = camera1_rst_pin;
+       }
+
+       gpio_direction_output(cam_dev->pwdn_pin, cam_dev->pwdn_act);
+
+       msleep(20);
+
+       gpio_direction_output(cam_dev->pwdn_pin, !(cam_dev->pwdn_act));
+
+       msleep(20);
+
+       gpio_direction_output(cam_dev->rst_pin, 0);
+
+       msleep(20);
+
+       gpio_direction_output(cam_dev->rst_pin, 1);
+
+       msleep(20);
+
+       pr_info("aml_cams: %s init OK\n", cam_dev->name);
+
+}
+
+void aml_cam_uninit(struct aml_cam_info_s *cam_dev)
+{
+       int ret;
+
+       pr_info("aml_cams: %s uninit.\n", cam_dev->name);
+       /*set camera power disable*/
+       /*coding style need: msleep < 20ms can sleep for up to 20ms*/
+       /*msleep(20);*/
+
+       ret = gpio_direction_output(cam_dev->pwdn_pin, cam_dev->pwdn_act);
+       if (ret < 0)
+               pr_info("aml_cam_uninit pwdn_pin output pwdn_act failed\n");
+
+       msleep(20);
+
+       ret = gpio_direction_output(cam_dev->rst_pin, 0);
+       if (ret < 0)
+               pr_info("aml_cam_uninit rst_pin output rst_pin failed\n");
+
+       msleep(20);
+
+       if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB)
+               GXBB_cam_disable_clk(cam_dev->spread_spectrum);
+       else if ((get_cpu_type() == MESON_CPU_MAJOR_ID_G12A) ||
+               (get_cpu_type() == MESON_CPU_MAJOR_ID_G12B))
+               GX12_cam_disable_clk(cam_dev->spread_spectrum);
+       else
+               cam_disable_clk(cam_dev->spread_spectrum);
+}
+
+void aml_cam_flash(struct aml_cam_info_s *cam_dev, int is_on)
+{
+       int ret;
+
+       if (cam_dev->flash_support) {
+               pr_info("aml_cams: %s flash %s.\n",
+                   cam_dev->name, is_on ? "on" : "off");
+
+               ret = gpio_direction_output(cam_dev->flash_ctrl_pin,
+                           cam_dev->flash_ctrl_level ? is_on : !is_on);
+               if (ret < 0)
+                       pr_info("aml_cam_flash flash_ctrl_pin output failed\n");
+       }
+}
+
+void aml_cam_torch(struct aml_cam_info_s *cam_dev, int is_on)
+{
+       int ret;
+
+       if (cam_dev->torch_support) {
+               pr_info("aml_cams: %s torch %s.\n",
+           cam_dev->name, is_on ? "on" : "off");
+
+               ret = gpio_direction_output(cam_dev->torch_ctrl_pin,
+                           cam_dev->torch_ctrl_level ? is_on : !is_on);
+               if (ret < 0)
+                       pr_info("aml_cam_torch torch_ctrl_pin output failed\n");
+       }
+}
+
+static struct list_head cam_head = LIST_HEAD_INIT(cam_head);
+
+#define DEBUG_DUMP_CAM_INFO
+
+static int fill_csi_dev(struct device_node *p_node,
+                       struct aml_cam_info_s *cam_dev)
+{
+       const char *str;
+       int ret = 0;
+
+       ret = of_property_read_string(p_node, "clk_channel", &str);
+       if (ret) {
+               pr_info("failed to read clock channel, \"a or b\"\n");
+               cam_dev->clk_channel = CLK_CHANNEL_A;
+       } else {
+               pr_info("clock channel:clk %s\n", str);
+               if (strncmp("a", str, 1) == 0)
+                       cam_dev->clk_channel = CLK_CHANNEL_A;
+               else
+                       cam_dev->clk_channel = CLK_CHANNEL_B;
+       }
+
+       return ret;
+
+}
+static int fill_cam_dev(struct device_node *p_node,
+                       struct aml_cam_info_s *cam_dev)
+{
+       const char *str;
+       int ret = 0;
+       const struct aml_cam_dev_info_s *cam_info = NULL;
+       struct device_node *adapter_node = NULL;
+       struct i2c_adapter *adapter = NULL;
+       unsigned int mclk = 0;
+       unsigned int vcm_mode = 0;
+
+       if (!p_node || !cam_dev)
+               return -1;
+
+       ret = of_property_read_u32(p_node, "front_back", &cam_dev->front_back);
+       if (ret) {
+               pr_info("get camera name failed!\n");
+               goto err_out;
+       }
+
+       ret = of_property_read_string(p_node, "cam_name", &cam_dev->name);
+       if (ret) {
+               pr_info("get camera name failed!\n");
+               goto err_out;
+       }
+
+       cam_dev->pwdn_pin = of_get_named_gpio(p_node, "gpio_pwdn-gpios", 0);
+       if (cam_dev->pwdn_pin == 0) {
+               pr_info("%s: failed to map gpio_pwdn !\n", cam_dev->name);
+               goto err_out;
+       }
+
+       ret = gpio_request(cam_dev->pwdn_pin, "camera");
+       if (ret < 0)
+               pr_info("aml_cam_init pwdn_pin request failed\n");
+
+       if (!cam_dev->front_back)
+               camera0_pwdn_pin = cam_dev->pwdn_pin;
+       else
+               camera1_pwdn_pin = cam_dev->pwdn_pin;
+
+       cam_dev->rst_pin = of_get_named_gpio(p_node, "gpio_rst-gpios", 0);
+       if (cam_dev->rst_pin == 0) {
+               pr_info("%s: failed to map gpio_rst !\n", cam_dev->name);
+               goto err_out;
+       }
+       ret = gpio_request(cam_dev->rst_pin, "camera");
+       if (ret < 0)
+               pr_info("aml_cam_init rst_pin request failed\n");
+
+       if (!cam_dev->front_back)
+               camera0_rst_pin = cam_dev->rst_pin;
+       else
+               camera1_rst_pin = cam_dev->rst_pin;
+
+       cam_info = get_cam_info_by_name(cam_dev->name);
+       if (cam_info == NULL) {
+               pr_info("camera %s is not support\n", cam_dev->name);
+               ret = -1;
+               goto err_out;
+       }
+
+       of_property_read_u32(p_node, "spread_spectrum",
+               &cam_dev->spread_spectrum);
+
+       ret = of_property_read_string(p_node, "bt_path", &str);
+       if (ret) {
+               pr_info("failed to read bt_path\n");
+               cam_dev->bt_path = BT_PATH_GPIO;
+       } else {
+               pr_info("bt_path :%d\n", cam_dev->bt_path);
+               if (strncmp("csi", str, 3) == 0)
+                       cam_dev->bt_path = BT_PATH_CSI2;
+               else if (strncmp("gpio_b", str, 6) == 0)
+                       cam_dev->bt_path = BT_PATH_GPIO_B;
+               else
+                       cam_dev->bt_path = BT_PATH_GPIO;
+       }
+       of_property_read_u32(p_node, "bt_path_count", &cam_dev->bt_path_count);
+       bt_path_count = cam_dev->bt_path_count;
+
+       cam_dev->pwdn_act = cam_info->pwdn;
+       cam_dev->i2c_addr = cam_info->addr;
+       pr_info("camer addr: 0x%x\n", cam_dev->i2c_addr);
+       pr_info("camer i2c bus: %d\n", cam_dev->i2c_bus_num);
+
+       adapter_node = of_parse_phandle(p_node, "camera-i2c-bus", 0);
+       if (adapter_node) {
+               adapter = of_find_i2c_adapter_by_node(adapter_node);
+               of_node_put(adapter_node);
+               if (adapter == NULL) {
+                       pr_err("%s, failed parse camera-i2c-bus\n",
+                          __func__);
+                       return -1;
+               }
+       }
+
+       if (adapter && cam_info->probe_func) {
+               aml_cam_init(cam_dev);
+               if (cam_info->probe_func(adapter) != 1) {
+                       pr_info("camera %s not on board\n", cam_dev->name);
+                       ret = -1;
+                       aml_cam_uninit(cam_dev);
+                       goto err_out;
+               }
+               aml_cam_uninit(cam_dev);
+       } else {
+               pr_err("can not do probe function\n");
+               ret = -1;
+               goto err_out;
+       }
+
+       of_property_read_u32(p_node, "mirror_flip", &cam_dev->m_flip);
+       of_property_read_u32(p_node, "vertical_flip", &cam_dev->v_flip);
+       of_property_read_u32(p_node, "vdin_path", &cam_dev->vdin_path);
+
+       ret = of_property_read_string(p_node, "max_cap_size", &str);
+       if (ret)
+               pr_info("failed to read max_cap_size\n");
+       else {
+               pr_info("max_cap_size :%s\n", str);
+               cam_dev->max_cap_size = get_res_size(str);
+       }
+       if (cam_dev->max_cap_size == SIZE_NULL)
+               cam_dev->max_cap_size = cam_info->max_cap_size;
+
+       ret = of_property_read_u32(p_node, "mclk", &mclk);
+       if (ret)
+               cam_dev->mclk = 24000;
+       else
+               cam_dev->mclk = mclk;
+
+       ret = of_property_read_u32(p_node, "vcm_mode", &vcm_mode);
+       if (ret)
+               cam_dev->vcm_mode = 0;
+       else
+               cam_dev->vcm_mode = vcm_mode;
+       pr_info("vcm mode is %d\n", cam_dev->vcm_mode);
+
+       ret = of_property_read_u32(p_node, "flash_support",
+                                  &cam_dev->flash_support);
+       if (cam_dev->flash_support) {
+               of_property_read_u32(p_node, "flash_ctrl_level",
+                                    &cam_dev->flash_ctrl_level);
+               ret = of_property_read_string(p_node, "flash_ctrl_pin", &str);
+               if (ret) {
+                       pr_info("%s: failed to get flash_ctrl_pin!\n",
+                       cam_dev->name);
+                       cam_dev->flash_support = 0;
+               } else {
+                       cam_dev->flash_ctrl_pin = of_get_named_gpio(p_node,
+                           "flash_ctrl_pin", 0);
+                       if (cam_dev->flash_ctrl_pin == 0) {
+                               pr_info("%s: failed to map flash_ctrl_pin !\n",
+                           cam_dev->name);
+                               cam_dev->flash_support = 0;
+                               cam_dev->flash_ctrl_level = 0;
+                       }
+                       ret = gpio_request(cam_dev->flash_ctrl_pin, "camera");
+                       if (ret < 0)
+                               pr_info("camera flash_ctrl_pin request failed\n");
+               }
+       }
+
+       ret = of_property_read_u32(p_node, "torch_support",
+                                  &cam_dev->torch_support);
+       if (cam_dev->torch_support) {
+               of_property_read_u32(p_node, "torch_ctrl_level",
+                                    &cam_dev->torch_ctrl_level);
+               ret = of_property_read_string(p_node, "torch_ctrl_pin", &str);
+               if (ret) {
+                       pr_info("%s: failed to get torch_ctrl_pin!\n",
+                           cam_dev->name);
+                       cam_dev->torch_support = 0;
+               } else {
+                       cam_dev->torch_ctrl_pin = of_get_named_gpio(p_node,
+                          "torch_ctrl_level", 0);
+                       ret = gpio_request(cam_dev->torch_ctrl_pin, "camera");
+                       if (ret < 0)
+                               pr_info("camera torch_ctrl_pin request failed\n");
+               }
+       }
+
+       ret = of_property_read_string(p_node, "interface", &str);
+       if (ret) {
+               pr_info("failed to read camera interface \"mipi or dvp\"\n");
+               cam_dev->interface = CAM_DVP;
+       } else {
+               pr_info("camera interface:%s\n", str);
+               if (strncmp("dvp", str, 1) == 0)
+                       cam_dev->interface = CAM_DVP;
+               else
+                       cam_dev->interface = CAM_MIPI;
+       }
+       if (cam_dev->interface == CAM_MIPI) {
+               ret = fill_csi_dev(p_node, cam_dev);
+               if (ret < 0)
+                       goto err_out;
+       }
+
+       ret = of_property_read_string(p_node, "bayer_fmt", &str);
+       if (ret) {
+               pr_info("failed to read camera bayer fmt\n");
+               cam_dev->bayer_fmt = TVIN_GBRG;
+       } else {
+               pr_info("color format:%s\n", str);
+               if (strncmp("BGGR", str, 4) == 0)
+                       cam_dev->bayer_fmt = TVIN_BGGR;
+               else if (strncmp("RGGB", str, 4) == 0)
+                       cam_dev->bayer_fmt = TVIN_RGGB;
+               else if (strncmp("GBRG", str, 4) == 0)
+                       cam_dev->bayer_fmt = TVIN_GBRG;
+               else if (strncmp("GRBG", str, 4) == 0)
+                       cam_dev->bayer_fmt = TVIN_GRBG;
+               else
+                       cam_dev->bayer_fmt = TVIN_GBRG;
+       }
+
+       ret = of_property_read_string(p_node, "config_path", &cam_dev->config);
+       if (ret)
+               pr_info("failed to read config_file path\n");
+       else
+               pr_info("config path :%s\n", cam_dev->config);
+
+#ifdef DEBUG_DUMP_CAM_INFO
+       pr_info("=======cam %s info=======\n"
+              "i2c_bus_num: %d\n"
+              "pwdn_act: %d\n"
+              "front_back: %d\n"
+              "m_flip: %d\n"
+              "v_flip: %d\n"
+              "i2c_addr: 0x%x\n"
+              "config path:%s\n"
+              "bt_path:%d\n",
+              cam_dev->name, cam_dev->i2c_bus_num, cam_dev->pwdn_act,
+              cam_dev->front_back, cam_dev->m_flip, cam_dev->v_flip,
+              cam_dev->i2c_addr, cam_dev->config, cam_dev->bt_path);
+#endif /* DEBUG_DUMP_CAM_INFO */
+
+       ret = 0;
+
+err_out:
+       return ret;
+}
+
+static int do_read_work(char argn, char **argv)
+{
+       unsigned int dev_addr, reg_addr, data_len = 1, result;
+       unsigned int i2c_bus;
+       struct i2c_adapter *adapter;
+
+       if (argn < 4) {
+               pr_err("args num error");
+               return -1;
+       }
+
+       if (!strncmp(argv[1], "i2c_bus_ao", 9))
+               i2c_bus = 4;
+       else if (!strncmp(argv[1], "i2c_bus_0", 9))
+               i2c_bus = 0;
+       else if (!strncmp(argv[1], "i2c_bus_1", 9))
+               i2c_bus = 1;
+       else if (!strncmp(argv[1], "i2c_bus_2", 9))
+               i2c_bus = 2;
+       else if (!strncmp(argv[1], "i2c_bus_3", 9))
+               i2c_bus = 3;
+       else {
+               pr_err("bus name error!\n");
+               return -1;
+       }
+
+       adapter = i2c_get_adapter(i2c_bus);
+
+       if (adapter == NULL) {
+               pr_info("no adapter!\n");
+               return -1;
+       }
+
+       dev_addr = kstrtol(argv[2], 16, NULL);
+       reg_addr = kstrtol(argv[3], 16, NULL);
+       if (argn == 5) {
+               pr_info("argv[4] is %s\n", argv[4]);
+               data_len = kstrtol(argv[4], 16, NULL);
+       }
+
+       if (reg_addr > 256) {
+               if (data_len != 2) {
+                       result = aml_i2c_get_byte(adapter, dev_addr, reg_addr);
+                       pr_info("register [0x%04x]=0x%02x\n", reg_addr, result);
+               } else {
+                       result = aml_i2c_get_word(adapter, dev_addr, reg_addr);
+                       pr_info("register [0x%04x]=0x%04x\n", reg_addr, result);
+               }
+       } else {
+               if (data_len != 2) {
+                       result = aml_i2c_get_byte_add8(adapter,
+                       dev_addr, reg_addr);
+                       pr_info("register [0x%02x]=0x%02x\n", reg_addr, result);
+               } else {
+                       result = aml_i2c_get_word_add8(adapter,
+                       dev_addr, reg_addr);
+                       pr_info("register [0x%02x]=0x%04x\n", reg_addr, result);
+               }
+       }
+
+       return 0;
+}
+
+static int do_write_work(char argn, char **argv)
+{
+       unsigned int dev_addr, reg_addr, reg_val, data_len = 1, ret = 0;
+       unsigned int i2c_bus;
+       struct i2c_adapter *adapter;
+
+       if (argn < 5) {
+               pr_err("args num error");
+               return -1;
+       }
+
+       if (!strncmp(argv[1], "i2c_bus_0", 9))
+               i2c_bus = 0;
+       else if (!strncmp(argv[1], "i2c_bus_1", 9))
+               i2c_bus = 1;
+       else if (!strncmp(argv[1], "i2c_bus_2", 9))
+               i2c_bus = 2;
+       else if (!strncmp(argv[1], "i2c_bus_3", 9))
+               i2c_bus = 3;
+       else if (!strncmp(argv[1], "i2c_bus_ao", 9))
+               i2c_bus = 4;
+       else {
+               pr_err("bus name error!\n");
+               return -1;
+       }
+
+       adapter = i2c_get_adapter(i2c_bus);
+
+       if (adapter == NULL) {
+               pr_info("no adapter!\n");
+               return -1;
+       }
+
+       dev_addr = kstrtol(argv[2], 16, NULL);
+       reg_addr = kstrtol(argv[3], 16, NULL);
+       reg_val = kstrtol(argv[4], 16, NULL);
+       if (argn == 6)
+               data_len = kstrtol(argv[5], 16, NULL);
+       if (reg_addr > 256) {
+               if (data_len != 2) {
+                       if (aml_i2c_put_byte(adapter, dev_addr,
+                           reg_addr, reg_val) < 0) {
+                               pr_err("write error\n");
+                               ret = -1;
+                       } else {
+                               pr_info("write ok\n");
+                               ret = 0;
+                       }
+               } else {
+                       if (aml_i2c_put_word(adapter, dev_addr,
+                           reg_addr, reg_val) < 0) {
+                               pr_err("write error\n");
+                               ret = -1;
+                       } else {
+                               pr_info("write ok\n");
+                               ret = 0;
+                       }
+               }
+       } else {
+               if (data_len != 2) {
+                       if (aml_i2c_put_byte_add8(adapter, dev_addr,
+                           reg_addr, reg_val) < 0) {
+                               pr_err("write error\n");
+                               ret = -1;
+                       } else {
+                               pr_info("write ok\n");
+                               ret = 0;
+                       }
+               } else {
+                       if (aml_i2c_put_word_add8(adapter, dev_addr,
+                           reg_addr, reg_val) < 0) {
+                               pr_err("write error\n");
+                               ret = -1;
+                       } else {
+                               pr_info("write ok\n");
+                               ret = 0;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static struct class *cam_clsp;
+
+static ssize_t show_help(struct class *class, struct class_attribute *attr,
+                        char *buf)
+{
+       ssize_t size = 0;
+
+       pr_info(
+               "echo [read | write] i2c_bus_type device_address register_address [value] [data_len] > i2c_debug\n"
+               "i2c_bus_type are: i2c_bus_ao, i2c_bus_a, i2c_bus_b, i2c_bus_c, i2c_bus_d\n"
+               "e.g.: echo read i2c_bus_ao 0x3c 0x18 1\n"
+               "      echo write i2c_bus_ao 0x3c 0x18 0x24 1\n");
+       return size;
+}
+
+static ssize_t store_i2c_debug(struct class *class,
+                              struct class_attribute *attr, const char *buf,
+                              size_t count)
+{
+       int argn;
+       char *buf_work, *p, *para;
+       char cmd;
+       char *argv[6];
+
+       buf_work = kstrdup(buf, GFP_KERNEL);
+       p = buf_work;
+
+       for (argn = 0; argn < 6; argn++) {
+               para = strsep(&p, " ");
+               if (para == NULL)
+                       break;
+               argv[argn] = para;
+               pr_info("argv[%d] = %s\n", argn, para);
+       }
+
+       if (argn < 4 || argn > 6)
+               goto end;
+
+       cmd = argv[0][0];
+       switch (cmd) {
+       case 'r':
+       case 'R':
+               do_read_work(argn, argv);
+               break;
+       case 'w':
+       case 'W':
+               do_write_work(argn, argv);
+               break;
+       }
+       return count;
+end:
+       pr_err("error command!\n");
+       kfree(buf_work);
+       return -EINVAL;
+}
+
+static LIST_HEAD(info_head);
+
+static ssize_t cam_info_show(struct class *class, struct class_attribute *attr,
+                            char *buf)
+{
+       struct list_head *p;
+       struct aml_cam_info_s *cam_info = NULL;
+       int count = 0;
+
+       if (!list_empty(&info_head)) {
+               count += sprintf(&buf[count],
+           "name\t\tversion\t\t\t\tface_dir\t"
+                        "i2c_addr\n");
+               list_for_each(p, &info_head) {
+                       cam_info = list_entry(p, struct aml_cam_info_s,
+                           info_entry);
+               }
+       }
+       return count;
+}
+
+static struct class_attribute aml_cam_attrs[] = {
+       __ATTR(i2c_debug, 0644, show_help, store_i2c_debug),
+       __ATTR_RO(cam_info), __ATTR(help, 0644, show_help, NULL),
+       __ATTR_NULL,
+};
+
+int aml_cam_info_reg(struct aml_cam_info_s *cam_info)
+{
+       int ret = -1;
+
+       if (cam_info) {
+               list_add(&cam_info->info_entry, &info_head);
+               ret = 0;
+       }
+       return ret;
+}
+
+int aml_cam_info_unreg(struct aml_cam_info_s *cam_info)
+{
+       int ret = -1;
+       struct list_head *p, *n;
+       struct aml_cam_info_s *tmp_info = NULL;
+
+       if (cam_info) {
+               list_for_each_safe(p, n, &info_head) {
+                       tmp_info = list_entry(p, struct aml_cam_info_s,
+                                   info_entry);
+                       if (tmp_info == cam_info) {
+                               list_del(p);
+                               return 0;
+                       }
+               }
+       }
+       return ret;
+}
+
+static int aml_cams_probe(struct platform_device *pdev)
+{
+       struct device_node *cams_node = pdev->dev.of_node;
+       struct device_node *child;
+       struct i2c_board_info board_info;
+       struct i2c_adapter *adapter = NULL;
+       struct device_node *adapter_node = NULL;
+       struct timeval camera_start;
+       struct timeval camera_end;
+       int i;
+       unsigned long time_use = 0;
+
+       temp_cam = kzalloc(sizeof(struct aml_cam_info_s), GFP_KERNEL);
+       if (!temp_cam)
+               return -ENOMEM;
+
+       cam_pdev = pdev;
+       do_gettimeofday(&camera_start);
+       for_each_child_of_node(cams_node, child) {
+
+               memset(temp_cam, 0, sizeof(struct aml_cam_info_s));
+
+               if (fill_cam_dev(child, temp_cam))
+                       continue;
+
+               /*register exist camera*/
+               memset(&board_info, 0, sizeof(board_info));
+               strlcpy(board_info.type, temp_cam->name, I2C_NAME_SIZE);
+
+               adapter_node = of_parse_phandle(child, "camera-i2c-bus", 0);
+               if (adapter_node) {
+                       adapter = of_get_i2c_adapter_by_node(adapter_node);
+                       of_node_put(adapter_node);
+                       if (adapter == NULL) {
+                               pr_err("%s, failed parse camera-i2c-bus\n",
+                                  __func__);
+                               return -1;
+                       }
+               } else {
+                       pr_err("adapter node is NULL.\n");
+                       return -1;
+               }
+               board_info.addr = temp_cam->i2c_addr;
+               board_info.platform_data = temp_cam;
+               pr_info("new i2c device\n");
+               /*i2c_new_existing_device(adapter, &board_info)*/
+               i2c_new_device(adapter, &board_info);
+       }
+       do_gettimeofday(&camera_end);
+       time_use = (camera_end.tv_sec - camera_start.tv_sec) * 1000 +
+               (camera_end.tv_usec - camera_start.tv_usec) / 1000;
+       pr_info("camera probe cost time = %ldms\n", time_use);
+
+       pr_info("aml probe finish\n");
+       cam_clsp = class_create(THIS_MODULE, "aml_camera");
+       for (i = 0; aml_cam_attrs[i].attr.name; i++) {
+               if (class_create_file(cam_clsp, &aml_cam_attrs[i]) < 0)
+                       return -1;
+       }
+
+       return 0;
+}
+
+static int aml_cams_remove(struct platform_device *pdev)
+{
+       if (camera0_pwdn_pin != 0)
+               gpio_free(camera0_pwdn_pin);
+       if (camera0_rst_pin != 0)
+               gpio_free(camera0_rst_pin);
+       if (camera1_pwdn_pin != 0)
+               gpio_free(camera1_pwdn_pin);
+       if (camera1_rst_pin != 0)
+               gpio_free(camera1_rst_pin);
+
+       kfree(temp_cam);
+       temp_cam = NULL;
+
+       return 0;
+}
+
+static const struct of_device_id cams_prober_dt_match[] = {{
+               .compatible =
+               "amlogic, cams_prober",
+       }, {},
+};
+
+static struct platform_driver aml_cams_prober_driver = {
+       .probe = aml_cams_probe, .remove = aml_cams_remove, .driver = {
+               .name =
+               "aml_cams_prober", .owner = THIS_MODULE, .of_match_table =
+               cams_prober_dt_match,
+       },
+};
+
+static int __init aml_cams_prober_init(void)
+{
+       if (platform_driver_register(&aml_cams_prober_driver)) {
+               pr_err("aml_cams_probre_driver register failed\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __exit aml_cams_prober_exit(void)
+{
+       bt_path_count = 0;
+       platform_driver_unregister(&aml_cams_prober_driver);
+}
+
+module_init(aml_cams_prober_init);
+module_exit(aml_cams_prober_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Amlogic Cameras prober driver");
+
diff --git a/drivers/amlogic/media/camera/common/config_parser.c b/drivers/amlogic/media/camera/common/config_parser.c
new file mode 100644 (file)
index 0000000..9ee62e7
--- /dev/null
@@ -0,0 +1,1822 @@
+/*
+ * drivers/amlogic/media/camera/common/config_parser.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 "config_parser.h"
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+
+static struct file *fp;
+mm_segment_t fs;
+
+char *aet_key = "aet_start";
+char *hw_key = "hw_start";
+char *effect_key = "effect_start";
+char *capture_key = "capture_start";
+char *scenes_key = "scenes_start";
+char *wb_key = "wb_start";
+char *wave_key = "wave_start";
+char *lens_key = "lens_start";
+char *gamma_key = "gamma_start";
+char *wb_sensor_key = "mwb_sensor_start";
+char *version_key = "version_start";
+char *cm_key = "cm_start";
+char *nr_key = "nr_start";
+char *peaking_key = "peaking_start";
+
+struct buffer_para_s {
+       char *buffer;
+       int data_start;
+       int data_size;
+       int buffer_len;
+};
+
+void *realloc_mem(char *buffer, int new_size, int *old_size)
+{
+       char *tmp = vmalloc(new_size);
+
+       if (*old_size >= new_size) {
+               vfree(tmp);
+               return buffer;
+       }
+
+       if (tmp != NULL) {
+               memcpy(tmp, buffer, *old_size);
+               *old_size = new_size;
+               vfree(buffer);
+               return tmp;
+       } else
+               return NULL;
+}
+
+/*
+ ***************************************
+ *Name :   camera_open_config
+ *Input        :       *config_file
+ *Output       :       file size
+ *function :   open the firware file, and return total size
+ ***************************************
+ */
+
+int camera_open_config(const char *config_file)
+{
+       loff_t file_size;
+       struct inode *inode = NULL;
+
+       fp = filp_open(config_file, O_RDONLY, 0);
+       if (IS_ERR(fp)) {
+               pr_err("read config file error");
+               return -1;
+       }
+
+       inode = fp->f_path.dentry->d_inode;
+       file_size = inode->i_size;
+       fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       return file_size;
+
+}
+
+/*
+ ***********************************
+ *Name :       camera_read_config
+ *Input        :       offset
+ *length, read length
+ *buf, return buffer
+ *Output       :
+ *function     :       read data to buffer
+ ***********************************
+ */
+
+int camera_read_config(int offset, int length, char *buf)
+{
+       loff_t pos = offset;
+
+       vfs_read(fp, buf, length, &pos);
+       return 0;
+}
+
+/*
+ **********************************
+ *Name :       camera_close_config
+ *Input        :
+ *Output       :
+ *function     :       close file
+ **********************************
+ */
+
+int camera_close_config(void)
+{
+       set_fs(fs);
+       filp_close(fp, NULL);
+       return 0;
+}
+
+static int camera_read_buff(struct i2c_adapter *adapter,
+                           unsigned short i2c_addr, char *buf, int addr_len,
+                           int data_len)
+{
+       int i2c_flag = -1;
+
+       struct i2c_msg msgs[] = {{
+                       .addr = i2c_addr, .flags = 0,
+                       .len = addr_len, .buf = buf,
+               }, {
+                       .addr = i2c_addr, .flags = I2C_M_RD,
+                       .len = data_len, .buf = buf,
+               }
+       };
+
+       i2c_flag = i2c_transfer(adapter, msgs, 2);
+
+       return i2c_flag;
+}
+
+static int camera_write_buff(struct i2c_adapter *adapter,
+                            unsigned short i2c_addr, char *buf, int len)
+{
+       struct i2c_msg msg[] = {{
+                       .addr = i2c_addr, .flags = 0,    /* |I2C_M_TEN, */
+                       .len = len, .buf = buf,
+               }
+
+       };
+
+       if (i2c_transfer(adapter, msg, 1) < 0)
+               return -1;
+       else
+               return 0;
+}
+
+int my_i2c_put_byte(struct i2c_adapter *adapter, unsigned short i2c_addr,
+                   unsigned short addr, unsigned char data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       buff[2] = data;
+       if (camera_write_buff(adapter, i2c_addr, buff, 3) < 0)
+               return -1;
+       return 0;
+}
+
+int my_i2c_put_byte_add8(struct i2c_adapter *adapter, unsigned short i2c_addr,
+                        char *buf, int len)
+{
+       if (camera_write_buff(adapter, i2c_addr, buf, len) < 0)
+               return -1;
+       return 0;
+}
+
+int my_i2c_get_byte(struct i2c_adapter *adapter, unsigned short i2c_addr,
+                   unsigned short addr)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+
+       if (camera_read_buff(adapter, i2c_addr, buff, 2, 1) < 0)
+               return -1;
+       return buff[0];
+}
+
+int my_i2c_get_word(struct i2c_adapter *adapter, unsigned short i2c_addr)
+{
+       unsigned char buff[4];
+       unsigned short data;
+
+       buff[0] = 0;
+
+       if (camera_read_buff(adapter, i2c_addr, buff, 1, 2) < 0)
+               return -1;
+
+       data = buff[0];
+       data = (data << 8) | buff[1];
+
+       return data;
+}
+
+char *search_string(struct buffer_para_s *buf_para, int *offset, int *remained,
+                   char *start, char *end)
+{
+       char *iter, *pter, *buffer;
+       int data_start, data_size, buffer_len;
+       int add = 0;
+
+       buffer = buf_para->buffer;
+       data_start = buf_para->data_start;
+       data_size = buf_para->data_size;
+       buffer_len = buf_para->buffer_len;
+       iter = strstr(buffer + data_start, start);
+       while (iter == NULL) {
+               if (iter == NULL && *remained < strlen(start)) {
+                       pr_err("wrong config file");
+                       return NULL;
+               }
+               memset(buffer, 0, buffer_len);
+               if (*remained < BUFFER_SIZE) {
+                       camera_read_config(*offset - strlen(start),
+                               *remained, buffer); /* check bounds */
+                       *offset += *remained - strlen(start);
+                       data_size = *remained;
+                       *remained = 0;
+                       data_start = 0;
+               } else {
+                       camera_read_config(*offset - strlen(start),
+                               BUFFER_SIZE, buffer);/* check bounds */
+                       *offset += BUFFER_SIZE - strlen(start);
+                       data_size = BUFFER_SIZE;
+                       *remained -= BUFFER_SIZE;
+                       data_start = 0;
+               }
+               iter = strstr(buffer, start);
+       }
+       data_start = iter - buffer;
+       /*** check **/
+       if (data_start > 512) {
+               data_size -= data_start;
+               memmove(buffer, iter, data_size);
+               *(buffer + data_size) = '\0';
+               iter = buffer;
+               data_start = 0;
+       }
+       pter = strstr(iter + strlen(start), end);
+       while (pter == NULL) {
+               if (pter == NULL && *remained < strlen(end)) {
+                       pr_err("wrong config file");
+                       return NULL;
+               }
+               buffer =
+               (char *)realloc_mem(buffer, data_size + BUFFER_SIZE + 1,
+                       &buffer_len);
+               if (buffer == NULL) {
+                       pr_err("realloc failed\n");
+                       return NULL;
+               }
+               if (*remained < BUFFER_SIZE) {
+                       camera_read_config(*offset, *remained,
+                               buffer + data_size); /* check bounds */
+                       add = *remained;
+                       *offset += *remained;
+                       *remained = 0;
+               } else {
+                       camera_read_config(*offset, BUFFER_SIZE,
+                               buffer + data_size); /* check bounds */
+                       add = BUFFER_SIZE;
+                       *remained -= BUFFER_SIZE;
+                       *offset += BUFFER_SIZE;
+               }
+               *(buffer + data_size + add) = '\0';
+               pter = strstr(buffer + data_size - strlen(end), end);
+               data_size += add;
+       }
+       /* if realloc ,iter is invalid,so recalculate */
+       iter = buffer + data_start;
+       data_start = pter - buffer;
+
+       buf_para->buffer = buffer;
+       buf_para->data_start = data_start;
+       buf_para->data_size = data_size;
+       buf_para->buffer_len = buffer_len;
+       return iter;
+}
+
+char *search_key(struct buffer_para_s *buf_para, int *offset, int *remained)
+{
+       char *iter, *buffer;
+       int data_start, data_size, buffer_len;
+       int add = 0;
+
+       buffer = buf_para->buffer;
+       data_start = buf_para->data_start;
+       data_size = buf_para->data_size;
+       buffer_len = buf_para->buffer_len;
+
+       iter = strstr(buffer + data_start, "[");
+       while (iter == NULL) {
+               if (iter == NULL && *remained < 20) {
+                       pr_err("file end\n");
+                       return NULL;
+               }
+               memset(buffer, 0, buffer_len);
+               if (*remained < BUFFER_SIZE) {
+                       camera_read_config(*offset,
+                               *remained, buffer); /* check bounds */
+                       *offset += *remained;
+                       data_size = *remained;
+                       *remained = 0;
+                       data_start = 0;
+               } else {
+                       camera_read_config(*offset,
+                               BUFFER_SIZE, buffer); /* check bounds */
+                       *offset += BUFFER_SIZE;
+                       data_size = BUFFER_SIZE;
+                       *remained -= BUFFER_SIZE;
+                       data_start = 0;
+               }
+               iter = strstr(buffer, "[");
+       }
+       data_start = iter - buffer;
+       /*** check **/
+       if (data_start + 20 > data_size) { /* ensure we have an complete key */
+               buffer =
+               (char *)realloc_mem(buffer, data_size + BUFFER_SIZE + 1,
+                       &buffer_len);
+               if (buffer == NULL) {
+                       pr_err("realloc failed\n");
+                       return NULL;
+               }
+               if (*remained < BUFFER_SIZE) {
+                       camera_read_config(*offset, *remained,
+                               buffer + data_size); /* check bounds */
+                       add = *remained;
+                       *offset += *remained;
+                       *remained = 0;
+
+               } else {
+                       camera_read_config(*offset, BUFFER_SIZE,
+                               buffer + data_size); /* check bounds */
+                       add = BUFFER_SIZE;
+                       *remained -= BUFFER_SIZE;
+                       *offset += BUFFER_SIZE;
+               }
+               *(buffer + data_size + add) = '\0';
+               data_size += add;
+       }
+/* if realloc ,iter is invalid,so recalculate */
+       iter = buffer + data_start;
+
+       buf_para->buffer = buffer;
+       buf_para->data_start = data_start;
+       buf_para->data_size = data_size;
+       buf_para->buffer_len = buffer_len;
+       return iter;
+}
+
+int parse_head(char *buffer, int *sum)
+{
+       int ret;
+       char *iter;
+
+       iter = strstr(buffer, "sum");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       iter += 4; /* point to value */
+       ret = kstrtoint(iter, 10, sum);
+       return 0;
+}
+
+int parse_body_head(char *buffer, int *no, int check, char *name)
+{
+       int ret;
+       char *iter;
+
+       iter = strstr(buffer, "no");
+       iter += 3;
+       ret = kstrtoint(iter, 10, no);
+       iter = strstr(iter, "name");
+       iter += 5;
+       ret = kstrtos8(name, 16, iter);
+       return 0;
+}
+int parse_aet_element_info(char **iter, struct sensor_aet_info_s *info)
+{
+       int ret;
+
+       *iter = strstr(*iter, "export");
+       *iter += 7;
+       ret = kstrtouint(*iter, 16, &(info->fmt_main_fr));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->fmt_capture));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->fmt_hactive));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->fmt_vactive));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->fmt_rated_fr));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->fmt_min_fr));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->tbl_max_step));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->tbl_rated_step));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->tbl_max_gain));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(info->tbl_min_gain));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter,
+            16, &(info->format_transfer_parameter));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       return 0;
+
+}
+
+int parse_aet_element_tbl(char **iter, struct sensor_aet_s *tbl)
+{
+       int ret;
+
+       ret = kstrtouint(*iter, 16, &(tbl->exp));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->ag));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->vts));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->gain));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->fr));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       return 0;
+}
+
+int parse_last_aet_element_tbl(char **iter, struct sensor_aet_s *tbl)
+{
+       int ret;
+
+       ret = kstrtouint(*iter, 16, &(tbl->exp));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->ag));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->vts));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->gain));
+       *iter = strstr(*iter, ",");
+       *iter += 1;
+       ret = kstrtouint(*iter, 16, &(tbl->fr));
+       return 0;
+}
+
+int parse_effect(struct configure_s *cf, struct buffer_para_s *buf_para,
+                int *remained, int *offset)
+{
+       int ret1, ret2, ret3, sum, check, i;
+       char *iter;
+
+       iter = search_string(buf_para, offset, remained, "effect_start]",
+                            "[effect]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (ret1 != 0)
+               return -HEAD_FAILED;
+       cf->eff.sum = sum;
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset,
+                       remained, "[effect]", "[effect");
+               if (iter == NULL)
+                       return -WRONG_FORMAT;
+               ret2 = parse_body_head(iter, &(cf->eff.eff[check].num), check,
+                                     cf->eff.eff[check].name);
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               i = 0;
+               while (i < EFFECT_MAX && iter != NULL) {
+                       ret3 = kstrtouint(iter,
+                          16, &(cf->eff.eff[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               if (i != EFFECT_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+}
+
+int parse_aet(struct configure_s *cf, struct buffer_para_s *buf_para,
+             int *remained, int *offset)
+{
+       int sum, ret, check, i;
+       char *iter;
+
+       iter = search_string(buf_para, offset, remained, "aet_start]", "[aet]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret = parse_head(iter, &sum);
+       if (sum <= 0)
+               return -HEAD_FAILED;
+       cf->aet.sum = sum;
+       /**parser body***/
+       for (i = 0; i < sum; i++) {
+               cf->aet.aet[i].info =
+               kmalloc(sizeof(struct sensor_aet_info_s), 0);
+               if ((cf->aet.aet[i].info) == NULL) {
+                       while (i-- > 0)
+                               kfree(cf->aet.aet[i].info);
+                       return -NO_MEM;
+               }
+       } /* alloc head */
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset,
+                       remained, "[aet]", "[aet");
+               if (iter == NULL) {
+                       pr_err("aet wrong config format\n");
+                       ret = -WRONG_FORMAT;
+                       goto clean;
+               }
+               ret = parse_body_head(iter, &(cf->aet.aet[check].num), check,
+                                     cf->aet.aet[check].name);
+               if (ret != 0) {
+                       ret = -HEAD_FAILED;
+                       goto clean;
+               }
+               ret = parse_aet_element_info(&iter, cf->aet.aet[check].info);
+               if (ret != 0) {
+                       ret = -BODY_ELEMENT_FAILED;
+                       goto clean;
+               }
+
+               cf->aet.aet[check].aet_table =
+               vmalloc(sizeof(struct sensor_aet_s) *
+               (cf->aet.aet[check].info->tbl_max_step + 1));
+               if ((cf->aet.aet[check].aet_table) == NULL) {
+                       for (i = 0; i < check; i++)
+                               vfree(cf->aet.aet[i].aet_table);
+                       ret = -NO_MEM;
+                       goto clean;
+               }
+               for (i = 0; i <= cf->aet.aet[check].info->tbl_max_step; i++) {
+                       if (i == cf->aet.aet[check].info->tbl_max_step) {
+                               ret = parse_last_aet_element_tbl(
+                             &iter, &(cf->aet.aet[check].aet_table[i]));
+                       } else
+                               ret = parse_aet_element_tbl(&iter,
+                                           &(cf->aet.aet[check].aet_table[i]));
+                       if (ret != 0) {
+                               ret = -BODY_ELEMENT_FAILED;
+                               goto clean_table;
+                       }
+               }
+               check++;
+       }
+       return 0;
+
+clean_table:
+       for (i = 0; i <= check; i++)
+               vfree(cf->aet.aet[i].aet_table);
+clean:
+       for (i = 0; i < sum; i++)
+               kfree(cf->aet.aet[i].info);
+       return ret;
+}
+
+int parse_hw(struct configure_s *cf, struct buffer_para_s *buf_para,
+            int *remained, int *offset)
+{
+       int ret1, ret2, ret3, sum, check, i;
+       char *iter = NULL;
+       char *eter = NULL;
+
+       iter = search_string(buf_para, offset, remained, "hw_start]", "[hw]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (ret1 != 0)
+               return -HEAD_FAILED;
+       cf->hw.sum = sum;
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset, remained, "[hw]", "[hw");
+               if (iter == NULL)
+                       return -WRONG_FORMAT;
+               ret2 = parse_body_head(iter, &(cf->hw.hw[check].num), check,
+                                     cf->hw.hw[check].name);
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               eter = strstr(iter, ";");
+               if (eter == NULL)
+                       return -WRONG_FORMAT;
+               i = 0;
+               while (iter < eter) {
+                       ret3 = kstrtouint(iter,
+                          16, &(cf->hw.hw[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+}
+
+int parse_wb(struct configure_s *cf, struct buffer_para_s *buf_para,
+            int *remained, int *offset)
+{
+       int ret1, ret2, ret3, sum, check, i;
+       char *iter = NULL;
+       char *eter = NULL;
+
+       iter = search_string(buf_para, offset, remained, "wb_start]", "[wb]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (ret1 != 0)
+               return -HEAD_FAILED;
+       cf->wb.sum = sum;
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset, remained, "[wb]", "[wb");
+               if (iter == NULL)
+                       return -WRONG_FORMAT;
+               ret2 = parse_body_head(iter, &(cf->wb.wb[check].num), check,
+                                     cf->wb.wb[check].name);
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               eter = strstr(iter, ";");
+               if (eter == NULL)
+                       return -WRONG_FORMAT;
+               i = 0;
+               while (iter < eter) {
+                       ret3 = kstrtouint(iter,
+                          16, &(cf->wb.wb[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+
+               }
+               if (i != WB_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+
+}
+
+int parse_capture(struct configure_s *cf, struct buffer_para_s *buf_para,
+                 int *remained, int *offset)
+{
+       int ret1, ret2, ret3, sum, check, i;
+       char *iter = NULL;
+       char *eter = NULL;
+
+       iter = search_string(buf_para, offset, remained, "capture_start]",
+                            "[capture]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (ret1 != 0)
+               return -HEAD_FAILED;
+       cf->capture.sum = sum;
+       /* pr_err("capture sum:%d\n",sum); */
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset, remained, "[capture]",
+                                    "[capture");
+               if (iter == NULL) {
+                       pr_err("search wrong\n");
+                       return -WRONG_FORMAT;
+               }
+               ret2 = parse_body_head(iter,
+                               &(cf->capture.capture[check].num), check,
+                                     cf->capture.capture[check].name);
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               /* pr_err("name:%s\n",cf->capture.capture[check].name); */
+               iter = strstr(iter, "export");
+               if (iter == NULL) {
+                       pr_err("iter is NULL\n");
+                       return -WRONG_FORMAT;
+               }
+               iter += 7;
+               eter = strstr(iter, ";");
+               if (eter == NULL)
+                       return -WRONG_FORMAT;
+               i = 0;
+               while (iter < eter) {
+                       ret3 = kstrtouint(iter,
+                           16, &(cf->capture.capture[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               if (i != CAPTURE_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+
+}
+
+int parse_wave(struct configure_s *cf, struct buffer_para_s *buf_para,
+              int *remained, int *offset)
+{
+       int i, ret;
+       char *iter = NULL;
+       char *eter = NULL;
+
+       iter = search_string(buf_para, offset, remained, "wave_start]",
+                            "[wave_end]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       iter = strstr(iter, "export");
+       iter += 7;
+       eter = strstr(iter, ";");
+       if (eter == NULL)
+               return -WRONG_FORMAT;
+       i = 0;
+       while (iter < eter) {
+               ret = kstrtouint(iter, 16, &(cf->wave.export[i]));
+               /* pr_err("wave:%x\n",cf->wave.export[i]); */
+               iter = strstr(iter, ",");
+               i++;
+               if (iter == NULL)
+                       break;
+               iter += 1;
+       }
+       if (i != WAVE_MAX)
+               return -CHECK_LEN_FAILED;
+       return 0;
+}
+
+int parse_scene(struct configure_s *cf, struct buffer_para_s *buf_para,
+               int *remained, int *offset)
+{
+       int sum, ret1, ret2, ret3, check, i;
+       char *iter = NULL;
+       char *eter = NULL;
+
+       iter = search_string(buf_para, offset, remained, "scenes_start]",
+                            "[scenes]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (sum <= 0)
+               return -HEAD_FAILED;
+       cf->scene.sum = sum;
+
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset,
+                                       remained, "[scenes]", "[scenes");
+               if (iter == NULL) {
+                       pr_err("scene wrong config format\n");
+                       return -WRONG_FORMAT;
+               }
+               ret2 = parse_body_head(iter, &((cf->scene.scene[check]).num),
+                               check, (cf->scene.scene[check].name));
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               eter = strstr(iter, ";");
+               if (eter == NULL)
+                       return -WRONG_FORMAT;
+               i = 0;
+               while (iter < eter) {
+                       ret3 = kstrtouint(iter,
+                          16, &(cf->scene.scene[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               if (i != SCENE_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+}
+
+int parse_lens(struct configure_s *cf, struct buffer_para_s *buf_para,
+              int *remained, int *offset)
+{
+       int sum, ret1, ret2, ret3, check, i;
+       char *iter = NULL;
+       char *eter = NULL;
+
+       iter = search_string(buf_para, offset,
+                               remained, "lens_start]", "[lens]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (sum <= 0)
+               return -HEAD_FAILED;
+       cf->lens.sum = sum;
+
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset,
+                               remained, "[lens]", "[lens");
+               if (iter == NULL) {
+                       pr_err("lens wrong config format\n");
+                       return -WRONG_FORMAT;
+               }
+               ret2 = parse_body_head(iter,
+                               &((cf->lens.lens[check]).num),
+                               check,
+                               (cf->lens.lens[check].name));
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               eter = strstr(iter, ";");
+               if (eter == NULL)
+                       return -WRONG_FORMAT;
+               i = 0;
+               while (iter < eter) {
+                       ret3 = kstrtouint(iter,
+                          16, &(cf->lens.lens[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               if (i != LENS_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+}
+
+int parse_gamma(struct configure_s *cf, struct buffer_para_s *buf_para,
+               int *remained, int *offset)
+{
+       int i, ret;
+       char *iter;
+
+       iter = search_string(buf_para, offset, remained, "gamma_start]",
+                            "[gamma_end]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       iter = strstr(iter, "export");
+       iter += 7;
+       for (i = 0; i < GAMMA_MAX && iter != NULL;) {
+               ret = kstrtouint(iter, 16, &(cf->gamma.gamma_r[i]));
+               i++;
+               iter = strstr(iter, ",");
+               if (iter == NULL)
+                       break;
+               iter += 1;
+       }
+       if (i != GAMMA_MAX)
+               return -CHECK_LEN_FAILED;
+       for (i = 0; i < GAMMA_MAX && iter != NULL;) {
+               ret = kstrtouint(iter, 16, &(cf->gamma.gamma_g[i]));
+               i++;
+               iter = strstr(iter, ",");
+               if (iter == NULL)
+                       break;
+               iter += 1;
+       }
+       if (i != GAMMA_MAX)
+               return -CHECK_LEN_FAILED;
+       for (i = 0; i < GAMMA_MAX && iter != NULL;) {
+               ret = kstrtouint(iter,
+                  16, &(cf->gamma.gamma_b[i]));
+               i++;
+               iter = strstr(iter, ",");
+               if (iter == NULL)
+                       break;
+               iter += 1;
+       }
+       if (i != GAMMA_MAX)
+               return -CHECK_LEN_FAILED;
+       return 0;
+}
+
+int parse_wb_sensor(struct configure_s *cf, struct buffer_para_s *buf_para,
+                   int *remained, int *offset)
+{
+       int i, ret;
+       char *iter;
+
+       iter = search_string(buf_para, offset, remained, "mwb_sensor_start]",
+                            "[mwb_sensor_end]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       iter = strstr(iter, "export");
+       iter += 7;
+       i = 0;
+       while (i < WB_SENSOR_MAX && iter != NULL) {
+               ret = kstrtouint(iter, 16, &(cf->wb_sensor_data.export[i]));
+               /* pr_err("wb sensor:%x\n",cf->wb_sensor_data.export[i]); */
+               i++;
+               iter = strstr(iter, ",");
+               if (iter == NULL)
+                       break;
+               iter += 1;
+       }
+       if (i != WB_SENSOR_MAX)
+               return -CHECK_LEN_FAILED;
+       return 0;
+}
+
+int parse_version(struct configure_s *cf, struct buffer_para_s *buf_para,
+                 int *remained, int *offset)
+{
+       char *iter, *end;
+       int len = 0;
+
+       iter = search_string(buf_para, offset, remained, "version_start]",
+                            "[version_end]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       iter = strstr(iter, "Date");
+       iter += 5;
+       end = strstr(iter, "Module");
+       if (end == NULL)
+               return -WRONG_FORMAT;
+       len = end - iter;
+       memcpy(cf->version.date, iter, len);
+       cf->version.date[len] = '\0';
+
+       iter = end + 7;
+       end = strstr(iter, "Version");
+       if (end == NULL)
+               return -WRONG_FORMAT;
+       len = end - iter;
+       memcpy(cf->version.module, iter, len);
+       cf->version.module[len] = '\0';
+
+       iter = end + 8;
+       end = strstr(iter, "[version");
+       if (end == NULL)
+               return -WRONG_FORMAT;
+       len = end - iter;
+       memcpy(cf->version.version, iter, len);
+       cf->version.version[len] = '\0';
+       pr_info("version:%s", cf->version.version);
+       return 0;
+}
+
+int parse_cm(struct configure_s *cf, struct buffer_para_s *buf_para,
+            int *remained, int *offset)
+{
+       int i;
+       int ret;
+       char *iter;
+
+       iter = search_string(buf_para, offset,
+                       remained, "cm_start]", "[cm_end]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser body***/
+       iter = strstr(iter, "export");
+       iter += 7;
+       i = 0;
+       while (i < CM_MAX && iter != NULL) {
+               ret = kstrtouint(iter, 16, &(cf->cm.export[i]));
+               /* pr_err("cm:%x\n",cf->cm.export[i]); */
+               i++;
+               iter = strstr(iter, ",");
+               if (iter == NULL)
+                       break;
+               iter += 1;
+       }
+       if (i != CM_MAX)
+               return -CHECK_LEN_FAILED;
+       return 0;
+}
+
+int parse_nr(struct configure_s *cf, struct buffer_para_s *buf_para,
+            int *remained, int *offset)
+{
+       int ret1, ret2, ret3, sum, check, i;
+       char *iter;
+
+       iter = search_string(buf_para, offset, remained, "nr_start]", "[nr]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (ret1 != 0)
+               return -HEAD_FAILED;
+       cf->nr.sum = sum;
+       /* pr_err("nr sum:%d\n",sum); */
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset, remained, "[nr]", "[nr");
+               if (iter == NULL) {
+                       pr_err("search wrong\n");
+                       return -WRONG_FORMAT;
+               }
+               ret2 = parse_body_head(iter, &(cf->nr.nr[check].num), check,
+                                     cf->nr.nr[check].name);
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               i = 0;
+               while (i < NR_MAX && iter != NULL) {
+                       ret3 = kstrtouint(iter, 16,
+                           &(cf->nr.nr[check].export[i]));
+                       /* pr_err("nr:%x\n",cf->nr.nr[check].export[i]); */
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               if (i != NR_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+}
+
+int parse_peaking(struct configure_s *cf, struct buffer_para_s *buf_para,
+                 int *remained, int *offset)
+{
+       int ret1, ret2, ret3, sum, check, i;
+       char *iter;
+
+       iter = search_string(buf_para, offset, remained, "peaking_start]",
+                            "[peaking]");
+       if (iter == NULL)
+               return -WRONG_FORMAT;
+       /***parser head***/
+       ret1 = parse_head(iter, &sum);
+       if (ret1 != 0)
+               return -HEAD_FAILED;
+       cf->peaking.sum = sum;
+       /* pr_err("peaking sum:%d\n",sum); */
+       /**parser body***/
+       check = 0;
+       while (check < sum) {
+               iter = search_string(buf_para, offset, remained, "[peaking]",
+                                    "[peaking");
+               if (iter == NULL) {
+                       pr_err("search wrong\n");
+                       return -WRONG_FORMAT;
+               }
+               ret2 = parse_body_head(iter,
+                               &(cf->peaking.peaking[check].num), check,
+                               cf->peaking.peaking[check].name);
+               if (ret2 != 0)
+                       return -BODY_HEAD_FAILED;
+               iter = strstr(iter, "export");
+               iter += 7;
+               i = 0;
+               while (i < PEAKING_MAX && iter != NULL) {
+                       ret3 = kstrtouint(iter,
+                          16, &(cf->peaking.peaking[check].export[i]));
+                       i++;
+                       iter = strstr(iter, ",");
+                       if (iter == NULL)
+                               break;
+                       iter += 1;
+               }
+               if (i != PEAKING_MAX)
+                       return -CHECK_LEN_FAILED;
+               check++;
+       }
+       if (check != sum)
+               return -CHECK_FAILED;
+       return 0;
+}
+
+int parse_config(const char *path, struct configure_s *cf)
+{
+       char *buffer, *iter;
+       int file_size;
+       int remained_size;
+       int read_offset = 0;
+       int ret = 0;
+       struct buffer_para_s buf_para;
+
+       buffer = vmalloc(BUFFER_SIZE + 1);/*(char *)*/
+       if (buffer == NULL)
+               return -NO_MEM;
+
+       buf_para.buffer = buffer;
+
+       memset(cf, 0, sizeof(struct configure_s));
+       file_size = camera_open_config(path);
+       if (file_size < 0) {
+               pr_err("open failed :%d\n", file_size);
+               ret = -READ_ERROR;
+               goto clean_mem;
+       } else if (file_size == 0) {
+               pr_err("file is null\n");
+               ret = -READ_ERROR;
+               goto clean_all;
+       } else {
+               if (file_size < BUFFER_SIZE) {
+                       camera_read_config(0, file_size, buffer);
+                       remained_size = 0;
+                       read_offset = file_size;
+                       *(buffer + file_size) = '\0';
+               } else {
+                       camera_read_config(0, BUFFER_SIZE, buffer);
+                       remained_size = file_size - BUFFER_SIZE;
+                       read_offset = BUFFER_SIZE;
+                       *(buffer + BUFFER_SIZE) = '\0';
+               }
+       }
+       buf_para.data_start = 0;
+       buf_para.data_size = read_offset;
+       buf_para.buffer_len = BUFFER_SIZE;
+
+       while (read_offset <= file_size) {
+               iter = search_key(&buf_para, &read_offset, &remained_size);
+               if (iter == NULL) {
+                       pr_info("finish parse file\n");
+                       return 0;
+               }
+               iter += 1;
+               buf_para.data_start += 1;
+               switch (*iter) {
+               case 'a':
+                       if (memcmp(iter, aet_key, strlen(aet_key)) == 0) {
+                               cf->aet_valid = 1;
+                               ret = parse_aet(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->aet_valid = 0;
+                                       pr_err("aet invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(aet_key);
+                       break;
+               case 'h':
+                       if (memcmp(iter, hw_key, strlen(hw_key)) == 0) {
+                               cf->hw_valid = 1;
+                               ret = parse_hw(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->hw_valid = 0;
+                                       pr_err("hw invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(hw_key);
+                       break;
+               case 'e':
+                       if (memcmp(iter, effect_key, strlen(effect_key)) == 0) {
+                               cf->effect_valid = 1;
+                               ret = parse_effect(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->effect_valid = 0;
+                                       pr_err("effect invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(effect_key);
+                       break;
+               case 'w':
+                       if (*(iter + 1) == 'b') {
+                               if (memcmp(iter, wb_key, strlen(wb_key)) == 0) {
+                                       cf->wb_valid = 1;
+                                       ret = parse_wb(cf, &buf_para,
+                                               &remained_size, &read_offset);
+                                       if (ret != 0) {
+                                               cf->wb_valid = 0;
+                                               pr_err("wb invalid :%d\n", ret);
+                                               goto clean_all;
+                                       }
+                               } else
+                                       buf_para.data_start += strlen(wb_key);
+                       } else if (*(iter + 1) == 'a') {
+                               if (memcmp(iter, wave_key,
+                                               strlen(wave_key)) == 0) {
+                                       cf->wave_valid = 1;
+                                       ret = parse_wave(cf, &buf_para,
+                                               &remained_size, &read_offset);
+                                       if (ret != 0) {
+                                               cf->wave_valid = 0;
+                                               pr_err("wave invalid :%d\n",
+                                                       ret);
+                                               goto clean_all;
+                                       }
+                               } else
+                                       buf_para.data_start += strlen(wave_key);
+                       } else
+                               buf_para.data_start += 1;
+
+                       break;
+               case 's':
+                       if (memcmp(iter, scenes_key,
+                                       strlen(scenes_key)) == 0) {
+                               cf->scene_valid = 1;
+                               ret = parse_scene(cf, &buf_para,
+                               &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->scene_valid = 0;
+                                       pr_err("scene invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(scenes_key);
+                       break;
+               case 'c':
+                       if (*(iter + 1) == 'a') {
+                               if (memcmp(iter, capture_key,
+                                               strlen(capture_key)) == 0) {
+                                       cf->capture_valid = 1;
+                                       ret = parse_capture(cf, &buf_para,
+                                               &remained_size, &read_offset);
+                                       if (ret != 0) {
+                                               cf->capture_valid = 0;
+                                               pr_err("capture invalid :%d\n",
+                                                       ret);
+                                               goto clean_all;
+                                       }
+                               } else
+                                       buf_para.data_start +=
+                                               strlen(capture_key);
+                       } else if (*(iter + 1) == 'm') {
+                               if (memcmp(iter, cm_key, strlen(cm_key)) == 0) {
+                                       cf->cm_valid = 1;
+                                       ret = parse_cm(cf, &buf_para,
+                                               &remained_size, &read_offset);
+                                       if (ret != 0) {
+                                               cf->cm_valid = 0;
+                                               pr_err("cm invalid :%d\n", ret);
+                                               goto clean_all;
+                                       }
+                               } else
+                                       buf_para.data_start += strlen(cm_key);
+                       } else
+                               buf_para.data_start += 1;
+                       break;
+               case 'l':
+                       if (memcmp(iter, lens_key, strlen(lens_key)) == 0) {
+                               cf->lens_valid = 1;
+                               ret = parse_lens(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->lens_valid = 0;
+                                       pr_err("lens invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(lens_key);
+                       break;
+               case 'g':
+                       if (memcmp(iter, gamma_key, strlen(gamma_key)) == 0) {
+                               cf->gamma_valid = 1;
+                               ret = parse_gamma(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->gamma_valid = 0;
+                                       pr_err("gamma invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(gamma_key);
+                       break;
+               case 'm':
+                       if (memcmp(iter, wb_sensor_key,
+                                       strlen(wb_sensor_key)) == 0) {
+                               cf->wb_sensor_data_valid = 1;
+                               ret = parse_wb_sensor(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->wb_sensor_data_valid = 0;
+                                       pr_err("wb sensor data invalid :%d\n",
+                                               ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(wb_sensor_key);
+                       break;
+               case 'v':
+                       if (memcmp(iter, version_key,
+                                       strlen(version_key)) == 0) {
+                               cf->version_info_valid = 1;
+                               ret = parse_version(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->version_info_valid = 0;
+                                       pr_err("version info invalid :%d\n",
+                                                                       ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(version_key);
+                       break;
+               case 'n':
+                       if (memcmp(iter, nr_key, strlen(nr_key)) == 0) {
+                               cf->nr_valid = 1;
+                               ret = parse_nr(cf, &buf_para,
+                                       &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->nr_valid = 0;
+                                       pr_err("nr invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(nr_key);
+                       break;
+               case 'p':
+                       if (memcmp(iter, peaking_key,
+                                       strlen(peaking_key)) == 0) {
+                               cf->peaking_valid = 1;
+                               ret = parse_peaking(cf, &buf_para,
+                                               &remained_size, &read_offset);
+                               if (ret != 0) {
+                                       cf->peaking_valid = 0;
+                                       pr_err("peaking invalid :%d\n", ret);
+                                       goto clean_all;
+                               }
+                       } else
+                               buf_para.data_start += strlen(peaking_key);
+                       break;
+               default:
+                       buf_para.data_start += 1;
+                       break;
+               }
+       }
+       ret = 0;
+
+clean_all:
+       camera_close_config();
+clean_mem:
+       vfree(buf_para.buffer);
+       return ret;
+}
+
+struct hw_para_s {
+       char name[20];
+       int size;
+       int *array;
+};
+
+struct hw_para_s hw_para[] = {
+       {"TOP", XML_TOP, NULL}, {"TP", XML_TP, NULL}, {"CG", XML_CG, NULL}, {
+               "LENS_SHADING", XML_LS, NULL
+       }, {"DFT", XML_DP, NULL}, {
+               "DMS", XML_DM, NULL
+       }, {"MATRIX", XML_CSC, NULL}, {
+               "PEAKING", XML_SH, NULL
+       }, {"NR", XML_NR, NULL}, {"AWB", XML_AWB, NULL},
+       {"AE", XML_AE, NULL}, {"AF", XML_AF, NULL}, {"BLNR", XML_BN, NULL}, {
+               "DBG", XML_DBG, NULL
+       }, {"GC", XML_GC, NULL}, {"", 0, NULL}
+};
+
+void init_hw_para(struct xml_default_regs_s *reg)
+{
+       hw_para[0].array = &(reg->top.reg_map[0]);
+       hw_para[1].array = &(reg->tp.reg_map[0]);
+       hw_para[2].array = &(reg->cg.reg_map[0]);
+       hw_para[3].array = &(reg->ls.reg_map[0]);
+       hw_para[4].array = &(reg->dp.reg_map[0]);
+       hw_para[5].array = &(reg->dm.reg_map[0]);
+       hw_para[6].array = &(reg->csc.reg_map[0]);
+       hw_para[7].array = &(reg->sharp.reg_map[0]);
+       hw_para[8].array = &(reg->nr.reg_map[0]);
+       hw_para[9].array = &(reg->awb_reg.reg_map[0]);
+       hw_para[10].array = &(reg->ae_reg.reg_map[0]);
+       hw_para[11].array = &(reg->af_reg.reg_map[0]);
+       hw_para[12].array = &(reg->bn.reg_map[0]);
+       hw_para[13].array = &(reg->dbg.reg_map[0]);
+       hw_para[14].array = &(reg->gc.reg_map[0]);
+}
+
+/* call back functions */
+
+unsigned int get_aet_max_step(void *priv)
+{
+       struct camera_priv_data_s *camera_priv_data =
+               (struct camera_priv_data_s *)priv;
+       if (camera_priv_data == NULL ||
+                       camera_priv_data->sensor_aet_info == NULL) {
+               pr_err("get_aet_max_step null\n");
+               WARN_ON((!camera_priv_data) ||
+                (!camera_priv_data->sensor_aet_info));
+       }
+       return camera_priv_data->sensor_aet_info->tbl_max_step;
+}
+
+unsigned int get_aet_max_gain(void *priv)
+{
+       struct camera_priv_data_s *camera_priv_data =
+               (struct camera_priv_data_s *)priv;
+       if (camera_priv_data == NULL ||
+                       camera_priv_data->sensor_aet_info == NULL) {
+               pr_err("get_aet_max_gain null\n");
+               WARN_ON((!camera_priv_data) ||
+                (!camera_priv_data->sensor_aet_info));
+       }
+       return camera_priv_data->sensor_aet_info->tbl_max_gain;
+}
+
+unsigned int get_aet_min_gain(void *priv)
+{
+       struct camera_priv_data_s *camera_priv_data =
+               (struct camera_priv_data_s *)priv;
+       if (camera_priv_data == NULL ||
+                       camera_priv_data->sensor_aet_info == NULL) {
+               pr_err("get_aet_min_gain null\n");
+               WARN_ON((!camera_priv_data) ||
+                (!camera_priv_data->sensor_aet_info));
+       }
+       return camera_priv_data->sensor_aet_info->tbl_min_gain;
+}
+
+unsigned int get_aet_current_step(void *priv)
+{
+       struct camera_priv_data_s *camera_priv_data =
+               (struct camera_priv_data_s *)priv;
+       if (camera_priv_data == NULL ||
+                       camera_priv_data->sensor_aet_info == NULL) {
+               pr_err("get_aet_current_step null\n");
+               WARN_ON((!camera_priv_data) ||
+                (!camera_priv_data->sensor_aet_info));
+       }
+       return camera_priv_data->sensor_aet_step;
+}
+
+unsigned int get_aet_current_gain(void *priv)
+{
+       struct sensor_aet_s *sensor_aet_table;
+       unsigned int sensor_aet_step;
+       struct camera_priv_data_s *camera_priv_data =
+               (struct camera_priv_data_s *)priv;
+       if (camera_priv_data == NULL)
+               WARN_ON(!camera_priv_data);
+
+       sensor_aet_table =
+               camera_priv_data->sensor_aet_table;
+       sensor_aet_step = camera_priv_data->sensor_aet_step;
+
+       if (sensor_aet_table == NULL) {
+               pr_err("get_aet_current_gain null\n");
+               WARN_ON(!sensor_aet_table);
+       }
+       return sensor_aet_table[sensor_aet_step].gain;
+}
+
+unsigned int get_aet_new_gain(void *priv, unsigned int new_step)
+{
+       struct camera_priv_data_s *camera_priv_data =
+               (struct camera_priv_data_s *)priv;
+       struct sensor_aet_s *sensor_aet_table;
+
+       if (camera_priv_data == NULL)
+               WARN_ON(!camera_priv_data);
+       sensor_aet_table =
+               camera_priv_data->sensor_aet_table;
+       if (sensor_aet_table == NULL) {
+               pr_err("get_aet_current_gain null\n");
+               WARN_ON(!sensor_aet_table);
+       }
+       return sensor_aet_table[new_step].gain;
+}
+
+int generate_para(struct cam_parameter_s *para, struct para_index_s pindex,
+                 struct configure_s *cf)
+{
+       int i = 0;
+       int j = 0;
+       struct xml_scenes_s *scene;
+       struct xml_default_regs_s *reg;
+       struct xml_effect_manual_s *effect;
+       struct xml_wb_manual_s *wb;
+       struct xml_capture_s *capture;
+       struct wave_s *wave;
+
+       /**init callback func**/
+       para->cam_function.set_af_new_step = NULL;
+       if (cf->aet_valid == 1) {
+               para->cam_function.get_aet_current_step = get_aet_current_step;
+               para->cam_function.get_aet_max_step = get_aet_max_step;
+               para->cam_function.get_aet_current_gain = get_aet_current_gain;
+               para->cam_function.get_aet_min_gain = get_aet_min_gain;
+               para->cam_function.get_aet_max_gain = get_aet_max_gain;
+               para->cam_function.get_aet_gain_by_step = get_aet_new_gain;
+
+       }
+       /**init scenes**/
+       if (cf->scene_valid == 1) {
+               para->xml_scenes =
+                       vmalloc(sizeof(struct xml_scenes_s));
+               if (para->xml_scenes == NULL) {
+                       pr_err("alloc mem failed\n");
+                       return -ENOMEM;
+               }
+               scene = para->xml_scenes;
+               memcpy(&(scene->ae),
+                       cf->scene.scene[pindex.scenes_index].export,
+                       AE_LEN * sizeof(unsigned int));
+               memcpy(&(scene->awb),
+                       cf->scene.scene[pindex.scenes_index].export + AE_LEN,
+                       AWB_LEN * sizeof(unsigned int));
+               memcpy(&(scene->af),
+               cf->scene.scene[pindex.scenes_index].export +
+               (AE_LEN + AWB_LEN),
+               AF_LEN * sizeof(unsigned int));
+       } else
+               para->xml_scenes = NULL;
+
+       /**init hw**/
+       if (cf->hw_valid == 1) {
+               para->xml_regs_map = vmalloc(sizeof(struct xml_default_regs_s));
+               if (para->xml_regs_map == NULL) {
+                       pr_err("alloc mem failed\n");
+                       return -ENOMEM;
+               }
+               reg = para->xml_regs_map;
+               init_hw_para(reg);
+               for (i = 0; i < cf->hw.sum; i++) {
+                       if ((strcmp(hw_para[i].name, cf->hw.hw[i].name)) == 0) {
+                               for (j = 0; j < hw_para[i].size; j++)
+                                       hw_para[i].array[j] =
+                                               cf->hw.hw[i].export[j];
+                       }
+               }
+
+       } else
+               para->xml_regs_map = NULL;
+       /** init gamma **/
+       if (cf->gamma_valid == 1) {
+               if (para->xml_regs_map == NULL) {
+                       para->xml_regs_map =
+                               vmalloc(sizeof(struct xml_default_regs_s));
+                       if (para->xml_regs_map == NULL) {
+                               pr_err("alloc mem failed\n");
+                               return -ENOMEM;
+                       }
+               }
+               reg = para->xml_regs_map;
+               memcpy(reg->lut_gc.gamma_r, cf->gamma.gamma_r,
+                      GAMMA_MAX * sizeof(unsigned short));
+               memcpy(reg->lut_gc.gamma_g, cf->gamma.gamma_g,
+                      GAMMA_MAX * sizeof(unsigned short));
+               memcpy(reg->lut_gc.gamma_b, cf->gamma.gamma_b,
+                      GAMMA_MAX * sizeof(unsigned short));
+       }
+       /**init effect**/
+       if (cf->effect_valid == 1) {
+               para->xml_effect_manual =
+                       kmalloc(sizeof(struct xml_effect_manual_s), 0);
+               if (para->xml_effect_manual == NULL) {
+                       pr_err("alloc mem failed\n");
+                       return -ENOMEM;
+               }
+               effect = para->xml_effect_manual;
+               memcpy(effect->csc.reg_map,
+               cf->eff.eff[pindex.effect_index].export,
+               EFFECT_MAX * sizeof(unsigned int));
+       } else
+               para->xml_effect_manual = NULL;
+       /**init wb**/
+       if (cf->wb_valid == 1) {
+               para->xml_wb_manual =
+                       kmalloc(sizeof(struct xml_wb_manual_s), 0);
+               if (para->xml_wb_manual == NULL) {
+                       pr_err("alloc mem failed\n");
+                       return -ENOMEM;
+               }
+               wb = para->xml_wb_manual;
+               memcpy(wb->reg_map, cf->wb.wb[pindex.wb_index].export,
+                      2 * sizeof(unsigned int));
+       } else
+               para->xml_wb_manual = NULL;
+
+       /**init capture**/
+       if (cf->capture_valid == 1) {
+               para->xml_capture = vmalloc(sizeof(struct xml_capture_s));
+               if (para->xml_capture == NULL) {
+                       pr_err("alloc mem failed\n");
+                       return -ENOMEM;
+               }
+               capture = para->xml_capture;
+               capture->ae_try_max_cnt = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[0]);
+               capture->sigle_count = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[3]);
+               capture->skip_step = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[4]);
+               capture->multi_capture_num = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[5]);
+               capture->af_mode = (enum cam_scanmode_e)(cf->capture.
+                       capture[pindex.capture_index].export[2]);
+               capture->eyetime = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[6]);
+               capture->pretime = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[7]);
+               capture->postime = (unsigned int)(cf->capture.
+                       capture[pindex.capture_index].export[8]);
+       } else
+               para->xml_capture = NULL;
+       /**init wave**/
+       if (cf->wave_valid == 1) {
+               para->xml_wave = kmalloc(sizeof(struct wave_s), 0);
+               if (para->xml_wave == NULL) {
+                       pr_err("alloc mem failed\n");
+                       return -ENOMEM;
+               }
+               wave = para->xml_wave;
+               memcpy(wave, cf->wave.export, WAVE_MAX * sizeof(unsigned int));
+       } else
+               para->xml_wave = NULL;
+       return 0;
+}
+
+void free_para(struct cam_parameter_s *para)
+{
+       if (para->xml_peripheral != NULL) {
+               kfree(para->xml_peripheral);
+               para->xml_peripheral = NULL;
+       }
+       if (para->xml_scenes != NULL) {
+               vfree(para->xml_scenes);
+               para->xml_scenes = NULL;
+       }
+       if (para->xml_regs_map != NULL) {
+               vfree(para->xml_regs_map);
+               para->xml_regs_map = NULL;
+       }
+       if (para->xml_effect_manual != NULL) {
+               kfree(para->xml_effect_manual);
+               para->xml_effect_manual = NULL;
+       }
+       if (para->xml_wb_manual != NULL) {
+               kfree(para->xml_wb_manual);
+               para->xml_wb_manual = NULL;
+       }
+       if (para->xml_capture != NULL) {
+               vfree(para->xml_capture);
+               para->xml_capture = NULL;
+       }
+       if (para->xml_wave != NULL) {
+               kfree(para->xml_wave);
+               para->xml_wave = NULL;
+       }
+}
+
+int update_fmt_para(int width, int height, struct cam_parameter_s *para,
+                   struct para_index_s *pindex, struct configure_s *cf)
+{
+       int i = 0;
+       struct xml_default_regs_s *reg;
+
+       if (cf->lens_valid == 1) {
+               while (i < cf->lens.sum) {
+                       if (cf->lens.lens[i].export[0] == width &&
+                   cf->lens.lens[i].export[1] == height)
+                               break;
+                       i++;
+               }
+               if (i < cf->lens.sum)
+                       pindex->lens_index = i;
+               else {
+                       pr_info("width:%x,height:%x no match lens param\n",
+                   width, height);
+                       pindex->lens_index = 0;
+               }
+               /** init lens **/
+               if (para->xml_regs_map == NULL) {
+                       para->xml_regs_map =
+                       vmalloc(sizeof(struct xml_default_regs_s));
+                       if (para->xml_regs_map == NULL) {
+                               pr_err("alloc mem failed\n");
+                               return -ENOMEM;
+                       }
+               }
+               reg = para->xml_regs_map;
+               memcpy(reg->lnsd.reg_map,
+               cf->lens.lens[pindex->lens_index].export + 2,
+          (LENS_MAX - 2) * sizeof(unsigned int));
+       }
+
+       i = 0;
+       if (cf->nr_valid == 1) {
+               while (i < cf->nr.sum) {
+                       if (cf->nr.nr[i].export[0] == width &&
+                       cf->nr.nr[i].export[1] == height)
+                               break;
+                       i++;
+               }
+               if (i < cf->nr.sum)
+                       pindex->nr_index = i;
+               else {
+                       pr_info("width:%x,height:%x no match nr param\n",
+                   width, height);
+                       pindex->nr_index = 0;
+               }
+               /** init nr **/
+               if (para->xml_regs_map == NULL) {
+                       para->xml_regs_map =
+                       vmalloc(sizeof(struct xml_default_regs_s));
+                       if (para->xml_regs_map == NULL) {
+                               pr_err("alloc mem failed\n");
+                               return -ENOMEM;
+                       }
+               }
+               reg = para->xml_regs_map;
+               memcpy(reg->nr.reg_map, cf->nr.nr[pindex->nr_index].export + 2,
+                      (NR_MAX - 2) * sizeof(unsigned int));
+       }
+
+       i = 0;
+       if (cf->peaking_valid == 1) {
+               while (i < cf->peaking.sum) {
+                       if (cf->peaking.peaking[i].export[0] == width &&
+                               cf->peaking.peaking[i].export[1] == height)
+                               break;
+                       i++;
+               }
+               if (i < cf->peaking.sum)
+                       pindex->peaking_index = i;
+               else {
+                       pr_info("width:%x,height:%x no match peaking param\n",
+                       width, height);
+                       pindex->peaking_index = 0;
+               }
+               /** init sharp **/
+               if (para->xml_regs_map == NULL) {
+                       para->xml_regs_map =
+                       vmalloc(sizeof(struct xml_default_regs_s));
+                       if (para->xml_regs_map == NULL) {
+                               pr_err("alloc mem failed\n");
+                               return -ENOMEM;
+                       }
+               }
+               reg = para->xml_regs_map;
+               memcpy(reg->sharp.reg_map,
+                      cf->peaking.peaking[pindex->peaking_index].export + 2,
+                      (PEAKING_MAX - 2) * sizeof(unsigned int));
+       }
+       return 0;
+}
diff --git a/drivers/amlogic/media/camera/common/config_parser.h b/drivers/amlogic/media/camera/common/config_parser.h
new file mode 100644 (file)
index 0000000..c5e7802
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * drivers/amlogic/media/camera/common/config_parser.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 CONFIG_PARSER
+#define CONFIG_PARSER
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/i2c.h>
+#include <linux/string.h>
+#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
+
+#define EFFECT_ITEM_MAX 16
+#define AET_ITEM_MAX 32
+#define HW_ITEM_MAX 16
+#define WB_ITEM_MAX 10
+#define CAPTURE_ITEM_MAX 9
+#define NR_ITEM_MAX 5
+#define PEAKING_ITEM_MAX 5
+#define LENS_ITEM_MAX 5
+#define SCENE_ITEM_MAX 1
+#define EFFECT_MAX 18
+#define HW_MAX 64
+#define WB_MAX 2
+#define GAMMA_MAX 257
+#define SCENE_MAX 281
+#define WB_SENSOR_MAX 4
+#define CAPTURE_MAX 8
+#define LENS_MAX 1027
+#define WAVE_MAX 12
+#define CM_MAX 188
+#define NR_MAX 15
+#define PEAKING_MAX 35
+#define AE_LEN 119
+#define AWB_LEN 120
+#define AF_LEN 42
+#define BUFFER_SIZE 1024
+
+enum error_code {
+       NO_MEM = 1,
+       READ_ERROR,
+       WRONG_FORMAT,
+       CHECK_LEN_FAILED,
+       CHECK_FAILED,
+       HEAD_FAILED,
+       BODY_HEAD_FAILED,
+       BODY_ELEMENT_FAILED,
+};
+
+struct effect_type {
+       int num;
+       char name[40];
+       unsigned int export[EFFECT_MAX];
+};
+
+struct effect_struct {
+       int sum;
+       struct effect_type eff[EFFECT_ITEM_MAX];
+};
+
+struct hw_type {
+       int num;
+       char name[40];
+       int export[HW_MAX];
+};
+
+struct hw_struct {
+       int sum;
+       struct hw_type hw[HW_ITEM_MAX];
+};
+
+struct wb_type {
+       int num;
+       char name[40];
+       int export[2];
+};
+
+struct wb_struct {
+       int sum;
+       struct wb_type wb[WB_ITEM_MAX];
+};
+
+struct scene_type {
+       int num;
+       char name[40];
+       int export[SCENE_MAX];
+};
+
+struct scene_struct {
+       int sum;
+       struct scene_type scene[SCENE_ITEM_MAX];
+};
+
+struct capture_type {
+       int num;
+       char name[40];
+       int export[CAPTURE_ITEM_MAX];
+};
+
+struct capture_struct {
+       int sum;
+       struct capture_type capture[CAPTURE_MAX];
+};
+
+struct sensor_aet_s {
+       unsigned int exp;
+       unsigned int ag;
+       unsigned int vts;
+       unsigned int gain;
+       unsigned int fr;
+};
+/* sensor_aet_t */
+
+struct sensor_aet_info_s {
+       unsigned int fmt_main_fr;
+       unsigned int fmt_capture; /* false: preview, true: capture */
+       unsigned int fmt_hactive;
+       unsigned int fmt_vactive;
+       unsigned int fmt_rated_fr;
+       unsigned int fmt_min_fr;
+       unsigned int tbl_max_step;
+       unsigned int tbl_rated_step;
+       unsigned int tbl_max_gain;
+       unsigned int tbl_min_gain;
+       unsigned int format_transfer_parameter;
+};
+/* sensor_aet_info_t */
+
+struct aet_type {
+       int num;
+       char name[40];
+       struct sensor_aet_info_s *info;
+       struct sensor_aet_s *aet_table;
+};
+
+struct aet_struct {
+       int sum;
+       struct aet_type aet[AET_ITEM_MAX];
+};
+
+struct wave_struct {
+       int export[WAVE_MAX];
+};
+
+struct lens_type {
+       int num;
+       char name[40];
+       int export[LENS_MAX];
+};
+
+struct lens_struct {
+       int sum;
+       struct lens_type lens[LENS_ITEM_MAX];
+};
+
+struct gamma_struct {
+       unsigned int gamma_r[GAMMA_MAX];
+       unsigned int gamma_g[GAMMA_MAX];
+       unsigned int gamma_b[GAMMA_MAX];
+};
+
+struct wb_sensor_struct {
+       int export[WB_SENSOR_MAX];
+};
+
+struct version_struct {
+       char date[40];
+       char module[30];
+       char version[30];
+};
+
+struct cm_struct {
+       int export[CM_MAX];
+};
+
+struct nr_type {
+       int num;
+       char name[40];
+       int export[NR_MAX];
+};
+
+struct nr_struct {
+       int sum;
+       struct nr_type nr[NR_ITEM_MAX];
+};
+
+struct peaking_type {
+       int num;
+       char name[40];
+       int export[PEAKING_MAX];
+};
+
+struct peaking_struct {
+       int sum;
+       struct peaking_type peaking[PEAKING_ITEM_MAX];
+};
+
+struct configure_s {
+       struct effect_struct eff;
+       int effect_valid;
+       struct hw_struct hw;
+       int hw_valid;
+       struct aet_struct aet;
+       int aet_valid;
+       struct capture_struct capture;
+       int capture_valid;
+       struct scene_struct scene;
+       int scene_valid;
+       struct wb_struct wb;
+       int wb_valid;
+       struct wave_struct wave;
+       int wave_valid;
+       struct lens_struct lens;
+       int lens_valid;
+       struct gamma_struct gamma;
+       int gamma_valid;
+       struct wb_sensor_struct wb_sensor_data;
+       int wb_sensor_data_valid;
+       struct version_struct version;
+       int version_info_valid;
+       struct cm_struct cm;
+       int cm_valid;
+       struct nr_struct nr;
+       int nr_valid;
+       struct peaking_struct peaking;
+       int peaking_valid;
+};
+
+struct para_index_s {
+       unsigned int effect_index;
+       unsigned int scenes_index;
+       unsigned int wb_index;
+       unsigned int capture_index;
+       unsigned int nr_index;
+       unsigned int peaking_index;
+       unsigned int lens_index;
+};
+
+struct wb_pair_t {
+       enum camera_wb_flip_e wb;
+       char *name;
+};
+
+struct effect_pair_t {
+       enum camera_special_effect_e effect;
+       char *name;
+};
+
+struct sensor_dg_s {
+       unsigned short r;
+       unsigned short g;
+       unsigned short b;
+       unsigned short dg_default;
+};
+
+struct camera_priv_data_s {
+       struct sensor_aet_info_s
+               *sensor_aet_info; /* point to 1 of up to 16 aet information */
+       struct sensor_aet_s *sensor_aet_table;
+       unsigned int sensor_aet_step; /* current step of the current aet */
+       struct configure_s *configure;
+};
+
+int parse_config(const char *path, struct configure_s *cf);
+int generate_para(struct cam_parameter_s *para, struct para_index_s pindex,
+                 struct configure_s *cf);
+void free_para(struct cam_parameter_s *para);
+int update_fmt_para(int width, int height, struct cam_parameter_s *para,
+                   struct para_index_s *pindex, struct configure_s *cf);
+
+unsigned int get_aet_current_step(void *priv);
+unsigned int get_aet_current_gain(void *pirv);
+unsigned int get_aet_min_gain(void *priv);
+unsigned int get_aet_max_gain(void *priv);
+unsigned int get_aet_max_step(void *priv);
+unsigned int get_aet_gain_by_step(void *priv, unsigned int new_step);
+
+int my_i2c_put_byte(struct i2c_adapter *adapter, unsigned short i2c_addr,
+                   unsigned short addr, unsigned char data);
+int my_i2c_put_byte_add8(struct i2c_adapter *adapter, unsigned short i2c_addr,
+                        char *buf, int len);
+int my_i2c_get_byte(struct i2c_adapter *adapter, unsigned short i2c_addr,
+                   unsigned short addr);
+int my_i2c_get_word(struct i2c_adapter *adapter, unsigned short i2c_addr);
+#endif
+
diff --git a/drivers/amlogic/media/camera/common/flashlight.c b/drivers/amlogic/media/camera/common/flashlight.c
new file mode 100644 (file)
index 0000000..51018d9
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * drivers/amlogic/media/camera/common/flashlight.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/cdev.h>
+#include <linux/types.h>
+
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/camera/flashlight.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+#define FLASHLIGHT_MODULE_NAME   "flashlight"
+#define FLASHLIGHT_DRIVER_NAME "flashlight"
+#define FLASHLIGHT_DEVICE_NAME   "flashlight"
+#define FLASHLIGHT_CLASS_NAME   "flashlight"
+
+static dev_t flashlight_devno;
+static struct cdev *flashlight_cdev;
+static struct device *devp;
+
+static enum aml_plat_flashlight_status_s flashlight_flag = FLASHLIGHT_OFF;
+
+static ssize_t flashlight_ctrl_store(struct class *cla,
+                              struct class_attribute *attr,
+                              const char *buf, size_t count);
+static ssize_t flashlightflag_show(struct class *cla,
+                                 struct class_attribute *attr, char *buf);
+static ssize_t flashlightflag_store(struct class *cla,
+                                 struct class_attribute *attr,
+                                 const char *buf, size_t count);
+static int flashlight_open(struct inode *inode, struct file *file);
+static int flashlight_release(struct inode *inode, struct file *file);
+static int flashlight_probe(struct platform_device *pdev);
+static int flashlight_remove(struct platform_device *pdev);
+
+static struct platform_driver flashlight_driver = {
+       .probe = flashlight_probe, .remove = flashlight_remove, .driver = {
+               .name =
+               FLASHLIGHT_DRIVER_NAME, .owner = THIS_MODULE,
+       },
+};
+
+static const struct file_operations flashlight_fops = {
+       .open = flashlight_open, .release = flashlight_release,
+};
+
+static struct class_attribute flashlight_class_attrs[] = {
+       __ATTR(flashlight_ctrl, 0644, NULL, flashlight_ctrl_store),
+       __ATTR(flashlightflag, 0644, flashlightflag_show,
+               flashlightflag_store),
+       __ATTR_NULL
+};
+static struct class flashlight_class = {
+               .name = FLASHLIGHT_CLASS_NAME,
+               .class_attrs = flashlight_class_attrs,
+               .owner = THIS_MODULE,
+       };
+
+static ssize_t flashlight_ctrl_store(struct class *cla,
+                              struct class_attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct aml_plat_flashlight_data_s *pdata = NULL;
+       struct device *dev = NULL;
+
+       dev = devp;
+       pdata = (struct aml_plat_flashlight_data_s *)dev->platform_data;
+       if (pdata == NULL) {
+               pr_err("%s platform data is required!\n", __func__);
+               return -1;
+       }
+       if (!strncmp(buf, "0", 1)) {
+               if (pdata->flashlight_off)
+                       pdata->flashlight_off();
+       } else if (!strncmp(buf, "1", 1)) {
+               if (pdata->flashlight_on)
+                       pdata->flashlight_on();
+       } else {
+               pr_err("%s:%s error!Not support this parameter\n",
+                      FLASHLIGHT_MODULE_NAME, __func__);
+               return -EINVAL;
+       }
+       return count;
+}
+
+static ssize_t flashlightflag_show(struct class *cla,
+                                 struct class_attribute *attr, char *buf)
+{
+       sprintf(buf, "%d", (int)flashlight_flag);
+       return strlen(buf);
+}
+
+static ssize_t flashlightflag_store(struct class *cla,
+                                 struct class_attribute *attr,
+                                 const char *buf, size_t count)
+{
+       if (!strlen(buf))
+               pr_info("%s parameter is required!\n", __func__);
+       flashlight_flag = (enum aml_plat_flashlight_status_s)(buf[0] - '0');
+       return count;
+}
+
+static int flashlight_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int flashlight_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int flashlight_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct aml_plat_flashlight_data_s *pdata = NULL;
+
+       ret = alloc_chrdev_region(&flashlight_devno, 0,
+                       1, FLASHLIGHT_DRIVER_NAME);
+       if (ret < 0) {
+               pr_err("%s:%s failed to allocate major number\n",
+                      FLASHLIGHT_MODULE_NAME, __func__);
+               ret = -ENODEV;
+               goto out;
+       }
+       ret = class_register(&flashlight_class);
+       if (ret < 0) {
+               pr_err("%s:%s  failed to register class\n",
+                       FLASHLIGHT_MODULE_NAME, __func__);
+               goto error1;
+       }
+       flashlight_cdev = cdev_alloc();
+       if (!flashlight_cdev) {
+               pr_err("%s:%s: failed to allocate memory\n",
+                       FLASHLIGHT_MODULE_NAME, __func__);
+               ret = -ENOMEM;
+               goto error2;
+       }
+       cdev_init(flashlight_cdev, &flashlight_fops);
+       flashlight_cdev->owner = THIS_MODULE;
+       ret = cdev_add(flashlight_cdev, flashlight_devno, 1);
+       if (ret) {
+               pr_err("%s:%s: failed to add device\n",
+                       FLASHLIGHT_MODULE_NAME, __func__);
+               goto error3;
+       }
+       devp = device_create(&flashlight_class, NULL, flashlight_devno, NULL,
+                            FLASHLIGHT_DEVICE_NAME);
+       if (IS_ERR(devp)) {
+               pr_err("%s:%s failed to create device node\n",
+                       FLASHLIGHT_MODULE_NAME, __func__);
+               ret = PTR_ERR(devp);
+               goto error3;
+       }
+       pr_info("%s:%s device %s created\n", FLASHLIGHT_MODULE_NAME,
+              __func__, FLASHLIGHT_DEVICE_NAME);
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "platform data is required!\n");
+               ret = -EINVAL;
+               goto error4;
+       }
+       devp->platform_data = pdata;
+       return 0;
+error4:
+       device_destroy(NULL, flashlight_devno);
+error3:
+       cdev_del(flashlight_cdev);
+error2:
+       class_unregister(&flashlight_class);
+error1:
+       unregister_chrdev_region(flashlight_devno, 1);
+out:
+       return ret;
+}
+
+static int flashlight_remove(struct platform_device *pdev)
+{
+       unregister_chrdev_region(flashlight_devno, 1);
+       class_unregister(&flashlight_class);
+       device_destroy(NULL, flashlight_devno);
+       cdev_del(flashlight_cdev);
+       return 0;
+}
+
+int set_flashlight(bool mode)
+{
+       struct aml_plat_flashlight_data_s *pdata = NULL;
+
+       if (devp && devp->platform_data) {
+               pdata = devp->platform_data;
+               if (!mode) {
+                       if (pdata->flashlight_off)
+                               pdata->flashlight_off();
+               } else {
+                       if (pdata->flashlight_on)
+                               pdata->flashlight_on();
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(set_flashlight);
+
+enum aml_plat_flashlight_status_s get_flashlightflag(void)
+{
+       return flashlight_flag;
+}
+EXPORT_SYMBOL(get_flashlightflag);
+
+static int __init flashlight_init(void)
+{
+       int ret = -1;
+
+       ret = platform_driver_register(&flashlight_driver);
+       if (ret != 0) {
+               pr_err("failed to register flashlight driver,error %d\n", ret);
+               return -ENODEV;
+       }
+       return ret;
+}
+
+static void __exit flashlight_exit(void)
+{
+       platform_driver_unregister(&flashlight_driver);
+}
+
+module_init(flashlight_init);
+module_exit(flashlight_exit);
+
+MODULE_DESCRIPTION("AMLOGIC flashlight driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("amlogic");
diff --git a/drivers/amlogic/media/camera/common/plat_ctrl.c b/drivers/amlogic/media/camera/common/plat_ctrl.c
new file mode 100644 (file)
index 0000000..44aa8bd
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * drivers/amlogic/media/camera/common/plat_ctrl.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+#include <media/videobuf-vmalloc.h>
+
+#include <linux/i2c.h>
+#include "plat_ctrl.h"
+
+/****************************************************************
+ *   i2c functions
+ * **************************************************************/
+static int camera_read_buff(struct i2c_client *client, char *buf, int addr_len,
+                           int data_len)
+{
+       int i2c_flag = -1;
+       struct i2c_msg msgs[] = {{
+                       .addr = client->addr, .flags = 0,
+           .len = addr_len, .buf = buf,
+               }, {
+                       .addr = client->addr, .flags = I2C_M_RD,
+           .len = data_len, .buf = buf,
+               }
+       };
+
+       i2c_flag = i2c_transfer(client->adapter, msgs, 2);
+
+       return i2c_flag;
+}
+
+static int camera_write_buff(struct i2c_client *client, char *buf, int len)
+{
+       struct i2c_msg msg[] = {{
+                       .addr = client->addr, .flags = 0,    /* |I2C_M_TEN, */
+                       .len = len, .buf = buf,
+               }
+
+       };
+
+       if (i2c_transfer(client->adapter, msg, 1) < 0) {
+               pr_err("i2c error\n");
+               return -1;
+       } else
+               return 0;
+}
+
+int i2c_get_byte(struct i2c_client *client, unsigned short addr)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+
+       if (camera_read_buff(client, buff, 2, 1) < 0)
+               return -1;
+       return buff[0];
+}
+
+int i2c_get_byte_add8(struct i2c_client *client, unsigned char addr)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)(addr & 0xff);
+
+       if (camera_read_buff(client, buff, 1, 1) < 0)
+               return -1;
+       return buff[0];
+}
+
+int i2c_get_word(struct i2c_client *client, unsigned short addr)
+{
+       unsigned short data;
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+
+       if (camera_read_buff(client, buff, 2, 2) < 0)
+               return -1;
+
+       data = buff[0];
+       data = (data << 8) | buff[1];
+       return data;
+}
+
+int i2c_put_byte(struct i2c_client *client, unsigned short addr,
+                unsigned char data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       buff[2] = data;
+       if (camera_write_buff(client, buff, 3) < 0)
+               return -1;
+       return 0;
+}
+
+int i2c_put_word(struct i2c_client *client, unsigned short addr,
+                unsigned short data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)((addr >> 8) & 0xff);
+       buff[1] = (unsigned char)(addr & 0xff);
+       buff[2] = (unsigned char)((data >> 8) & 0xff);
+       buff[3] = (unsigned char)(data & 0xff);
+
+       if (camera_write_buff(client, buff, 4) < 0)
+               return -1;
+       return 0;
+}
+
+int i2c_put_byte_add8_new(struct i2c_client *client, unsigned char addr,
+                         unsigned char data)
+{
+       unsigned char buff[4];
+
+       buff[0] = (unsigned char)(addr & 0xff);
+       buff[1] = (unsigned char)(data & 0xff);
+       if (camera_write_buff(client, buff, 2) < 0)
+               return -1;
+       return 0;
+}
+
+int i2c_put_byte_add8(struct i2c_client *client, char *buf, int len)
+{
+       if (camera_write_buff(client, buf, len) < 0)
+               return -1;
+       return 0;
+}
+
+int cam_i2c_send_msg(struct i2c_client *client, struct cam_i2c_msg_s i2c_msg)
+{
+       unsigned char buff[4];
+
+       switch (i2c_msg.type) {
+       case ADDR16_DATA16:
+               buff[0] = (unsigned char)((i2c_msg.addr >> 8) & 0xff);
+               buff[1] = (unsigned char)(i2c_msg.addr & 0xff);
+               buff[2] = (unsigned char)((i2c_msg.data >> 8) & 0xff);
+               buff[3] = (unsigned char)(i2c_msg.data & 0xff);
+               if (camera_write_buff(client, buff, 4) < 0)
+                       return -1;
+               break;
+       case ADDR16_DATA8:
+               buff[0] = (unsigned char)((i2c_msg.addr >> 8) & 0xff);
+               buff[1] = (unsigned char)(i2c_msg.addr & 0xff);
+               buff[2] = (unsigned char)(i2c_msg.data & 0xff);
+               if (camera_write_buff(client, buff, 3) < 0)
+                       return -1;
+               break;
+       case ADDR8_DATA16:
+               buff[0] = (unsigned char)(i2c_msg.addr & 0xff);
+               buff[1] = (unsigned char)((i2c_msg.data >> 8) & 0xff);
+               buff[2] = (unsigned char)(i2c_msg.data & 0xff);
+               if (camera_write_buff(client, buff, 3) < 0)
+                       return -1;
+               break;
+       case ADDR8_DATA8:
+               buff[0] = (unsigned char)(i2c_msg.addr & 0xff);
+               buff[1] = (unsigned char)(i2c_msg.data & 0xff);
+               if (camera_write_buff(client, buff, 2) < 0)
+                       return -1;
+               break;
+       case TIME_DELAY:
+               msleep(i2c_msg.data);
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
diff --git a/drivers/amlogic/media/camera/common/plat_ctrl.h b/drivers/amlogic/media/camera/common/plat_ctrl.h
new file mode 100644 (file)
index 0000000..6bcb6cb
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * drivers/amlogic/media/camera/common/plat_ctrl.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 _AMLOGIC_CAMERA_PLAT_CTRL_H
+#define _AMLOGIC_CAMERA_PLAT_CTRL_H
+
+#define ADDR8_DATA8            0
+#define ADDR16_DATA8           1
+#define ADDR16_DATA16          2
+#define ADDR8_DATA16           3
+#define TIME_DELAY             0xfe
+#define END_OF_SCRIPT                  0xff
+
+struct cam_i2c_msg_s {
+       unsigned char type;
+       unsigned short addr;
+       unsigned short data;
+};
+
+extern int i2c_get_byte(struct i2c_client *client, unsigned short addr);
+extern int i2c_get_word(struct i2c_client *client, unsigned short addr);
+extern int i2c_get_byte_add8(struct i2c_client *client, unsigned char addr);
+extern int i2c_put_byte(struct i2c_client *client, unsigned short addr,
+                       unsigned char data);
+extern int i2c_put_word(struct i2c_client *client, unsigned short addr,
+                       unsigned short data);
+extern int i2c_put_byte_add8_new(struct i2c_client *client, unsigned char addr,
+                                unsigned char data);
+extern int i2c_put_byte_add8(struct i2c_client *client, char *buf, int len);
+extern int cam_i2c_send_msg(struct i2c_client *client,
+                       struct cam_i2c_msg_s i2c_msg);
+
+#endif /* _AMLOGIC_CAMERA_PLAT_CTRL_H. */
diff --git a/drivers/amlogic/media/camera/common/vm.c b/drivers/amlogic/media/camera/common/vm.c
new file mode 100644 (file)
index 0000000..c994df2
--- /dev/null
@@ -0,0 +1,2309 @@
+/*
+ * drivers/amlogic/media/camera/common/vm.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/amlogic/media/vout/vinfo.h>
+#include <linux/amlogic/media/vout/vout_notify.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/media/frame_sync/ptsserv.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/vfm/vfm_ext.h>
+#include <linux/amlogic/media/ge2d/ge2d_cmd.h>
+#include <linux/amlogic/media/ge2d/ge2d.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/semaphore.h>
+#include <linux/sched/rt.h>
+#include <linux/platform_device.h>
+#include "vm_log.h"
+#include "vm.h"
+#include <linux/ctype.h>
+#include <linux/videodev2.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/amlogic/media/v4l_util/videobuf-res.h>
+
+#include <linux/amlogic/media/utils/amlog.h>
+#include <linux/amlogic/media/camera/vmapi.h>
+#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
+#include <linux/ctype.h>
+#include <linux/of.h>
+#include <linux/cdev.h>
+
+#include <linux/sizes.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_fdt.h>
+#include <linux/dma-contiguous.h>
+#include <linux/module.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/list.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+
+/*class property info.*/
+#include "vmcls.h"
+
+/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6 */
+#if 1
+#define GE2D_NV
+#endif
+
+#if 0
+static unsigned int amlvm_time_log_enable;
+module_param(amlvm_time_log_enable, uint, 0644);
+MODULE_PARM_DESC(amlvm_time_log_enable, "enable vm time log when get frames");
+#endif
+
+#define MAX_VF_POOL_SIZE 8
+
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+/*same as tvin pool*/
+static int VM_POOL_SIZE = 6;
+static int VF_POOL_SIZE = 6;
+static int VM_CANVAS_ID = 24;
+/*same as tvin pool*/
+#endif
+
+
+/*the counter of VM*/
+#define VM_MAX_DEVS            2
+
+static struct vm_device_s  *vm_device[VM_MAX_DEVS];
+
+/* static bool isvmused; */
+
+static void vm_cache_this_flush(unsigned int buf_start,
+                               unsigned int buf_size,
+                               struct vm_init_s *info);
+
+static inline void vm_vf_put_from_provider(struct vframe_s *vf,
+               unsigned int vdin_id);
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+#define INCPTR(p) ptr_atomic_wrap_inc(&p)
+#endif
+
+#ifdef CONFIG_AMLOGIC_CAPTURE_FRAME_ROTATE
+static int vmdecbuf_size[] = {
+       0x13B3000,/* 5M */
+       0xc00000,/* 3M */
+       0x753000,/* 2M */
+       0x4b0000,/* 1M3 */
+       0x300000,/* 1M */
+       0x12c000,/* VGA */
+       0x4b000,/* QVGA */
+};
+static struct v4l2_frmsize_discrete canvas_config_wh[] = {
+       {2624, 2624},
+       {2048, 2048},
+       {1600, 1600},
+       {1280, 1280},
+       {1024, 1024},
+       {640, 640},
+       {320, 320},
+};
+#else
+static int vmdecbuf_size[] = {
+       0xEE5000,/* 5M */
+       0x900000,/* 3M */
+       0x591000,/* 2M */
+       0x384000,/* 1M3 */
+       0x240000,/* 1M */
+       0xF0000,/* VGA */
+       0x3C000,/* QVGA */
+};
+static struct v4l2_frmsize_discrete canvas_config_wh[] = {
+       {2624, 1984},
+       {2048, 1536},
+       {1600, 1216},
+       {1280, 960},
+       {1024, 768},
+       {640, 512},
+       {320, 256},
+};
+#endif
+#define GE2D_ENDIAN_SHIFT        24
+#define GE2D_ENDIAN_MASK            (0x1 << GE2D_ENDIAN_SHIFT)
+#define GE2D_BIG_ENDIAN             (0 << GE2D_ENDIAN_SHIFT)
+#define GE2D_LITTLE_ENDIAN          (1 << GE2D_ENDIAN_SHIFT)
+
+#define PROVIDER_NAME "vm"
+
+static dev_t vm_devno;
+static struct class *vm_clsp;
+
+#define VM_DEV_NAME       "vm"
+#define RECEIVER_NAME  "vm"
+#define VM_CLS_NAME       "vm"
+
+static DEFINE_SPINLOCK(lock);
+
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+static inline void ptr_atomic_wrap_inc(u32 *ptr)
+{
+       u32 i = *ptr;
+
+       i++;
+       if (i >= VM_POOL_SIZE)
+               i = 0;
+       *ptr = i;
+}
+#endif
+
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+static struct vframe_s vfpool[MAX_VF_POOL_SIZE];
+static s32 vfbuf_use[MAX_VF_POOL_SIZE];
+static s32 fill_ptr, get_ptr, putting_ptr, put_ptr;
+#endif
+
+atomic_t waiting_flag = ATOMIC_INIT(0);
+
+static inline struct vframe_s *vm_vf_get_from_provider(unsigned int vdin_id);
+static inline struct vframe_s *vm_vf_peek_from_provider(unsigned int vdin_id);
+static inline void vm_vf_put_from_provider(struct vframe_s *vf,
+               unsigned int vdin_id);
+static struct vframe_receiver_op_s *vf_vm_unreg_provider(
+       struct vm_device_s *vdevp);
+static struct vframe_receiver_op_s *vf_vm_reg_provider(struct vm_device_s
+               *vdevp);
+static void stop_vm_task(struct vm_device_s *vdevp);
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+static int prepare_vframe(struct vframe_s *vf);
+#endif
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/*
+ ***********************************************
+ *
+ *   buffer op for video sink.
+ *
+ ***********************************************
+ */
+
+#ifdef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+static struct vframe_s *local_vf_peek(unsigned int vdin_id)
+{
+       struct vframe_s *vf = NULL;
+
+       vf = vm_vf_peek_from_provider(vdin_id);
+       if (vf) {
+               if (vm_device[vdin_id]->vm_skip_count > 0) {
+                       vm_device[vdin_id]->vm_skip_count--;
+                       vm_vf_get_from_provider(vdin_id);
+                       vm_vf_put_from_provider(vf, vdin_id);
+                       vf = NULL;
+               }
+       }
+       return vf;
+}
+
+static struct vframe_s *local_vf_get(unsigned int vdin_id)
+{
+       return vm_vf_get_from_provider(vdin_id);
+}
+
+static void local_vf_put(struct vframe_s *vf, unsigned int vdin_id)
+{
+       if (vf)
+               vm_vf_put_from_provider(vf, vdin_id);
+}
+#else
+
+static inline u32 index2canvas(u32 index)
+{
+       int i;
+       int start_canvas, count;
+       u32 canvas_tab[6];
+       struct vdin_v4l2_ops_s *vops = get_vdin_v4l2_ops();
+
+       vops->get_tvin_canvas_info(&start_canvas, &count);
+       VM_POOL_SIZE  = count;
+       VF_POOL_SIZE  = count;
+       VM_CANVAS_ID = start_canvas;
+       for (i = 0; i < count; i++)
+               canvas_tab[i] =  VM_CANVAS_INDEX + i;
+       return canvas_tab[index];
+}
+
+static struct vframe_s *vm_vf_peek(void *op_arg, unsigned int vdin_id)
+{
+       struct vframe_s *vf = NULL;
+
+       vf = vm_vf_peek_from_provider(vdin_id);
+       if (vf) {
+               if (vm_device[vdin_id]->vm_skip_count > 0) {
+                       vm_device[vdin_id]->vm_skip_count--;
+                       vm_vf_get_from_provider(vdin_id);
+                       vm_vf_put_from_provider(vf, vdin_id);
+                       vf = NULL;
+               }
+       }
+       return vf;
+}
+
+static struct vframe_s *vm_vf_get(void *op_arg, unsigned int vdin_id)
+{
+       return vm_vf_get_from_provider(vdin_id);
+}
+
+static void vm_vf_put(struct vframe_s *vf, void *op_arg)
+{
+       prepare_vframe(vf);
+}
+
+static int vm_vf_states(struct vframe_states *states, void *op_arg)
+{
+       return 0;
+}
+
+static struct vframe_s *local_vf_peek(void)
+{
+       if (get_ptr == fill_ptr)
+               return NULL;
+       return &vfpool[get_ptr];
+}
+
+static struct vframe_s *local_vf_get(unsigned int vdin_id)
+{
+       struct vframe_s *vf;
+
+       if (get_ptr == fill_ptr)
+               return NULL;
+       vf = &vfpool[get_ptr];
+       INCPTR(get_ptr);
+       return vf;
+}
+
+static void local_vf_put(struct vframe_s *vf, unsigned int vdin_id)
+{
+       int i;
+       int  canvas_addr;
+
+       if (!vf)
+               return;
+       INCPTR(putting_ptr);
+       for (i = 0; i < VF_POOL_SIZE; i++) {
+               canvas_addr = index2canvas(i);
+               if (vf->canvas0Addr == canvas_addr) {
+                       vfbuf_use[i] = 0;
+                       vm_vf_put_from_provider(vf, vdin_id);
+               }
+       }
+}
+#endif
+
+#if 0
+static int  local_vf_states(struct vframe_states *states)
+{
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&lock, flags);
+       states->vf_pool_size = VF_POOL_SIZE;
+
+       i = put_ptr - fill_ptr;
+       if  (i < 0)
+               i += VF_POOL_SIZE;
+       states->buf_free_num = i;
+
+       i = putting_ptr - put_ptr;
+       if  (i < 0)
+               i += VF_POOL_SIZE;
+       states->buf_recycle_num = i;
+
+       i = fill_ptr - get_ptr;
+       if  (i < 0)
+               i += VF_POOL_SIZE;
+       states->buf_avail_num = i;
+
+       spin_unlock_irqrestore(&lock, flags);
+       return 0;
+}
+#endif
+
+static int vm_receiver_event_fun(int type, void *data, void *private_data)
+{
+       struct vm_device_s *vdevp = (struct vm_device_s *)private_data;
+
+       switch (type) {
+       case VFRAME_EVENT_PROVIDER_VFRAME_READY:
+               /* if  (atomic_read(&waiting_flag))  { */
+               wake_up_interruptible(&vdevp->frame_ready);
+               /* atomic_set(&waiting_flag, 0); */
+               /* } */
+               /* up(&vb_start_sema); */
+               /* printk("vdin %d frame ready !!!!!\n", vdevp->index); */
+               break;
+       case VFRAME_EVENT_PROVIDER_START:
+               /* printk("vm register!!!!!\n"); */
+               vf_vm_reg_provider(vdevp);
+               vdevp->vm_skip_count = 0;
+               vdevp->test_zoom = 0;
+               break;
+       case VFRAME_EVENT_PROVIDER_UNREG:
+               /* printk("vm unregister!!!!!\n"); */
+               vm_local_init();
+               vf_vm_unreg_provider(vdevp);
+               /* printk("vm unregister succeed!!!!!\n"); */
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static struct vframe_receiver_op_s vm_vf_receiver = {
+       .event_cb = vm_receiver_event_fun
+};
+
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+static const struct vframe_operations_s vm_vf_provider = {
+       .peek = vm_vf_peek,
+       .get  = vm_vf_get,
+       .put  = vm_vf_put,
+       .vf_states = vm_vf_states,
+};
+
+static struct vframe_provider_s vm_vf_prov;
+#endif
+
+
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+int get_unused_vm_index(void)
+{
+       int i;
+
+       for (i = 0; i < VF_POOL_SIZE; i++) {
+               if (vfbuf_use[i] == 0)
+                       return i;
+       }
+       return -1;
+}
+static int prepare_vframe(struct vframe_s *vf)
+{
+       struct vframe_s *new_vf;
+       int index;
+
+       index = get_unused_vm_index();
+       if (index < 0)
+               return -1;
+       new_vf = &vfpool[fill_ptr];
+       memcpy(new_vf, vf, sizeof(struct vframe_s));
+       vfbuf_use[index]++;
+       INCPTR(fill_ptr);
+       return 0;
+}
+#endif
+
+/*
+ ************************************************
+ *
+ *   buffer op for decoder, camera, etc.
+ *
+ **************************************************
+ */
+
+/* static const vframe_provider_t *vfp = NULL; */
+
+void vm_local_init(void)
+{
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+       int i;
+
+       for (i = 0; i < MAX_VF_POOL_SIZE; i++)
+               vfbuf_use[i] = 0;
+       fill_ptr = get_ptr = putting_ptr = put_ptr = 0;
+#endif
+}
+
+static struct vframe_receiver_op_s *vf_vm_unreg_provider(
+       struct vm_device_s *vdevp)
+{
+       /* ulong flags; */
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+       vf_unreg_provider(&vm_vf_prov);
+#endif
+       stop_vm_task(vdevp);
+       /* spin_lock_irqsave(&lock, flags); */
+       /* vfp = NULL; */
+       /* spin_unlock_irqrestore(&lock, flags); */
+       return (struct vframe_receiver_op_s *)NULL;
+}
+EXPORT_SYMBOL(vf_vm_unreg_provider);
+
+static struct vframe_receiver_op_s *vf_vm_reg_provider(struct vm_device_s
+               *vdevp)
+{
+       ulong flags;
+       /* int ret; */
+       spin_lock_irqsave(&lock, flags);
+       spin_unlock_irqrestore(&lock, flags);
+       vm_buffer_init(vdevp);
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+       vf_reg_provider(&vm_vf_prov);
+#endif
+       start_vm_task(vdevp);
+#if 0
+       start_simulate_task();
+#endif
+       return &vm_vf_receiver;
+}
+EXPORT_SYMBOL(vf_vm_reg_provider);
+
+static inline struct vframe_s *vm_vf_peek_from_provider(unsigned int vdin_id)
+{
+       struct vframe_provider_s *vfp;
+       struct vframe_s *vf;
+       char name[20];
+
+       sprintf(name, "%s%d", RECEIVER_NAME, vdin_id);
+       vfp = vf_get_provider(name);
+       if (!(vfp && vfp->ops && vfp->ops->peek))
+               return NULL;
+       vf  = vfp->ops->peek(vfp->op_arg);
+       return vf;
+}
+
+static inline struct vframe_s *vm_vf_get_from_provider(unsigned int vdin_id)
+{
+       struct vframe_provider_s *vfp;
+       char name[20];
+
+       sprintf(name, "%s%d", RECEIVER_NAME, vdin_id);
+       vfp = vf_get_provider(name);
+       if (!(vfp && vfp->ops && vfp->ops->peek))
+               return NULL;
+       return vfp->ops->get(vfp->op_arg);
+}
+
+static inline void vm_vf_put_from_provider(struct vframe_s *vf,
+               unsigned int vdin_id)
+{
+       struct vframe_provider_s *vfp;
+       char name[20];
+
+       sprintf(name, "%s%d", RECEIVER_NAME, vdin_id);
+       vfp = vf_get_provider(name);
+       if (!(vfp && vfp->ops && vfp->ops->peek))
+               return;
+       vfp->ops->put(vf, vfp->op_arg);
+}
+
+/*
+ ***********************************************
+ *
+ *   main task functions.
+ *
+ ***********************************************
+ */
+
+static unsigned int print_ifmt;
+/* module_param(print_ifmt, unsigned int, 0644); */
+/* MODULE_PARM_DESC(print_ifmt, "print input format\n"); */
+
+static int get_input_format(struct vframe_s *vf)
+{
+       int format = GE2D_FORMAT_M24_NV21;
+
+       if (vf->type & VIDTYPE_VIU_422) {
+               if (vf->type & VIDTYPE_INTERLACE_BOTTOM)
+                       format =  GE2D_FORMAT_S16_YUV422 |
+                                 (GE2D_FORMAT_S16_YUV422B & (3 << 3));
+               else if (vf->type & VIDTYPE_INTERLACE_TOP)
+                       format =  GE2D_FORMAT_S16_YUV422 |
+                                 (GE2D_FORMAT_S16_YUV422T & (3 << 3));
+               else
+                       format =  GE2D_FORMAT_S16_YUV422;
+       } else if (vf->type & VIDTYPE_VIU_NV21) {
+               if (vf->type & VIDTYPE_INTERLACE_BOTTOM)
+                       format =  GE2D_FORMAT_M24_NV21 |
+                                 (GE2D_FORMAT_M24_NV21B & (3 << 3));
+               else if (vf->type & VIDTYPE_INTERLACE_TOP)
+                       format =  GE2D_FORMAT_M24_NV21 |
+                                 (GE2D_FORMAT_M24_NV21T & (3 << 3));
+               else
+                       format =  GE2D_FORMAT_M24_NV21;
+       } else {
+               if (vf->type & VIDTYPE_INTERLACE_BOTTOM)
+                       format =  GE2D_FORMAT_M24_YUV420 |
+                                 (GE2D_FMT_M24_YUV420B & (3 << 3));
+               else if (vf->type & VIDTYPE_INTERLACE_TOP)
+                       format =  GE2D_FORMAT_M24_YUV420 |
+                                 (GE2D_FORMAT_M24_YUV420T & (3 << 3));
+               else
+                       format =  GE2D_FORMAT_M24_YUV420;
+       }
+       if (print_ifmt == 1) {
+               pr_debug("VIDTYPE_VIU_NV21=%x, vf->type=%x\n",
+                        VIDTYPE_VIU_NV21, vf->type);
+               pr_debug("format=%x, w=%d, h=%d\n",
+                        format, vf->width, vf->height);
+               print_ifmt = 0;
+       }
+       return format;
+}
+
+#ifdef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+static int calc_zoom(int *top, int *left, int *bottom, int *right, int zoom)
+{
+       u32 screen_width, screen_height;
+       s32 start, end;
+       s32 video_top, video_left, temp;
+       u32 video_width, video_height;
+       u32 ratio_x = 0;
+       u32 ratio_y = 0;
+
+       if (zoom < 100)
+               zoom = 100;
+
+       video_top = *top;
+       video_left = *left;
+       video_width = *right - *left + 1;
+       video_height = *bottom - *top + 1;
+
+       screen_width = video_width * zoom / 100;
+       screen_height = video_height * zoom / 100;
+
+       ratio_x = (video_width << 18) / screen_width;
+       if (ratio_x * screen_width < (video_width << 18))
+               ratio_x++;
+       ratio_y = (video_height << 18) / screen_height;
+
+       /* vertical */
+       start = video_top + video_height / 2 - (video_height << 17) / ratio_y;
+       end   = (video_height << 18) / ratio_y + start - 1;
+
+       if (start < video_top) {
+               temp = ((video_top - start) * ratio_y) >> 18;
+               *top = temp;
+       } else
+               *top = 0;
+
+       temp = *top + (video_height * ratio_y >> 18);
+       *bottom = (temp <= (video_height - 1)) ? temp : (video_height - 1);
+
+       /* horizontal */
+       start = video_left + video_width / 2 - (video_width << 17) / ratio_x;
+       end   = (video_width << 18) / ratio_x + start - 1;
+       if (start < video_left) {
+               temp = ((video_left - start) * ratio_x) >> 18;
+               *left = temp;
+       } else
+               *left = 0;
+
+       temp = *left + (video_width * ratio_x >> 18);
+       *right = (temp <= (video_width - 1)) ? temp : (video_width - 1);
+       return 0;
+}
+#endif
+
+static int  get_input_frame(struct display_frame_s *frame, struct vframe_s *vf,
+                           int zoom)
+{
+       int ret = 0;
+       int top, left, bottom, right;
+
+       if (!vf)
+               return -1;
+
+       frame->frame_top = 0;
+       frame->frame_left = 0;
+       frame->frame_width = vf->width;
+       frame->frame_height = vf->height;
+       top = 0;
+       left = 0;
+       bottom = vf->height - 1;
+       right = vf->width - 1;
+#ifdef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+       ret = calc_zoom(&top, &left, &bottom, &right, zoom);
+#else
+       ret = get_curren_frame_para(&top, &left, &bottom, &right);
+#endif
+       if (ret >= 0) {
+               frame->content_top     =  top & (~1);
+               frame->content_left    =  left & (~1);
+               frame->content_width   =  vf->width - 2 * frame->content_left;
+               frame->content_height  =  vf->height - 2 * frame->content_top;
+       } else {
+               frame->content_top     = 0;
+               frame->content_left    =  0;
+               frame->content_width   = vf->width;
+               frame->content_height  = vf->height;
+       }
+       return 0;
+}
+
+static int get_output_format(int v4l2_format)
+{
+       int format = GE2D_FORMAT_S24_YUV444;
+
+       switch (v4l2_format) {
+       case V4L2_PIX_FMT_RGB565X:
+               format = GE2D_FORMAT_S16_RGB_565;
+               break;
+       case V4L2_PIX_FMT_YUV444:
+               format = GE2D_FORMAT_S24_YUV444;
+               break;
+       case V4L2_PIX_FMT_VYUY:
+               format = GE2D_FORMAT_S16_YUV422;
+               break;
+       case V4L2_PIX_FMT_BGR24:
+               format = GE2D_FORMAT_S24_RGB;
+               break;
+       case V4L2_PIX_FMT_RGB24:
+               format = GE2D_FORMAT_S24_BGR;
+               break;
+       case V4L2_PIX_FMT_NV12:
+#ifdef GE2D_NV
+               format = GE2D_FORMAT_M24_NV12;
+               break;
+#endif
+       case V4L2_PIX_FMT_NV21:
+#ifdef GE2D_NV
+               format = GE2D_FORMAT_M24_NV21;
+               break;
+#endif
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               format = GE2D_FORMAT_S8_Y;
+               break;
+       default:
+               break;
+       }
+       return format;
+}
+
+
+struct vm_dma_contig_memory {
+       u32 magic;
+       void *vaddr;
+       dma_addr_t dma_handle;
+       unsigned long size;
+       int is_userptr;
+};
+
+int is_need_ge2d_pre_process(struct vm_output_para output_para)
+{
+       int ret = 0;
+
+       switch (output_para.v4l2_format) {
+       case  V4L2_PIX_FMT_RGB565X:
+       case  V4L2_PIX_FMT_YUV444:
+       case  V4L2_PIX_FMT_VYUY:
+       case  V4L2_PIX_FMT_BGR24:
+       case  V4L2_PIX_FMT_RGB24:
+       case  V4L2_PIX_FMT_YUV420:
+       case  V4L2_PIX_FMT_YVU420:
+       case  V4L2_PIX_FMT_NV12:
+       case  V4L2_PIX_FMT_NV21:
+               ret = 1;
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+int is_need_sw_post_process(struct vm_output_para output_para)
+{
+       int ret = 0;
+
+       switch (output_para.v4l2_memory) {
+       case MAGIC_DC_MEM:
+       case MAGIC_RE_MEM:
+               goto exit;
+       case MAGIC_SG_MEM:
+       case MAGIC_VMAL_MEM:
+       default:
+               ret = 1;
+               break;
+       }
+exit:
+       return ret;
+}
+
+int get_canvas_index(int v4l2_format, int *depth)
+{
+       int canvas = vm_device[0]->vm_canvas[0];
+       *depth = 16;
+       switch (v4l2_format) {
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_VYUY:
+               canvas = vm_device[0]->vm_canvas[0];
+               *depth = 16;
+               break;
+       case V4L2_PIX_FMT_YUV444:
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB24:
+               canvas = vm_device[0]->vm_canvas[1];
+               *depth = 24;
+               break;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+#ifdef GE2D_NV
+               canvas = vm_device[0]->vm_canvas[2] |
+                   (vm_device[0]->vm_canvas[3] << 8);
+#else
+               canvas = vm_device[0]->vm_canvas[2] |
+                   (vm_device[0]->vm_canvas[3] << 8) |
+                   (vm_device[0]->vm_canvas[4] << 16);
+#endif
+               *depth = 12;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+       case V4L2_PIX_FMT_YVU420:
+               canvas = vm_device[0]->vm_canvas[5] |
+                   (vm_device[0]->vm_canvas[6] << 8) |
+                   (vm_device[0]->vm_canvas[7] << 16);
+               *depth = 12;
+               break;
+       default:
+               break;
+       }
+       return canvas;
+}
+
+int get_canvas_index_res(int ext_canvas, int v4l2_format, int *depth, int width,
+                        int height, unsigned int buf)
+{
+       int canvas = ext_canvas;
+       *depth = 16;
+       switch (v4l2_format) {
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_VYUY:
+               canvas = ext_canvas & 0xff;
+               *depth = 16;
+               canvas_config(canvas,
+                             (unsigned long)buf,
+                             width * 2, height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               break;
+       case V4L2_PIX_FMT_YUV444:
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB24:
+               canvas = ext_canvas & 0xff;
+               *depth = 24;
+               canvas_config(canvas,
+                             (unsigned long)buf,
+                             width * 3, height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               break;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+               canvas_config(ext_canvas & 0xff,
+                             (unsigned long)buf,
+                             width, height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config((ext_canvas & 0xff00) >> 8,
+                             (unsigned long)(buf + width * height),
+                             width, height / 2,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas = ext_canvas & 0xffff;
+               *depth = 12;
+               break;
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV420:
+               canvas_config(ext_canvas & 0xff,
+                             (unsigned long)buf,
+                             width, height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config((ext_canvas & 0xff00) >> 8,
+                             (unsigned long)(buf + width * height),
+                             width / 2, height / 2,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config((ext_canvas & 0xff0000) >> 16,
+                             (unsigned long)(buf + width * height * 5 / 4),
+                             width / 2, height / 2,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas = ext_canvas & 0xffffff;
+               *depth = 12;
+               break;
+       default:
+               break;
+       }
+       return canvas;
+}
+
+#if 0
+static void vm_dump_mem(char *path, void *phy_addr, struct vm_output_para *para)
+{
+       struct file *filp = NULL;
+       loff_t pos = 0;
+       void *buf = NULL;
+       unsigned int size = para->bytesperline * para->height;
+       mm_segment_t old_fs = get_fs();
+
+       set_fs(KERNEL_DS);
+       filp = filp_open(path, O_RDWR | O_CREAT, 0666);
+
+       if (IS_ERR(filp)) {
+               pr_err("create %s error.\n", path);
+               return;
+       }
+
+
+       buf = phys_to_virt((unsigned long)phy_addr);
+       vfs_write(filp, buf, size, &pos);
+
+       vfs_fsync(filp, 0);
+       filp_close(filp, NULL);
+       set_fs(old_fs);
+}
+
+static void vm_x_mem(char *path, struct vm_output_para *para)
+{
+       struct file *filp = NULL;
+       loff_t pos = 0;
+       void *buf = NULL;
+       unsigned int size = para->bytesperline * para->height;
+       unsigned int canvas_index = para->index;
+       struct canvas_s cv;
+       mm_segment_t old_fs = get_fs();
+
+       set_fs(KERNEL_DS);
+       filp = filp_open(path, O_CREAT | O_RDWR | O_APPEND, 0666);
+
+       if (IS_ERR(filp)) {
+               pr_err("failed to create %s, error %p.\n",
+                      path, filp);
+               return;
+       }
+
+       for (; canvas_index != 0; canvas_index >>= 8) {
+               canvas_read(canvas_index & 0xff, &cv);
+               /* printk("index=%lx,canvas.addr=%lx, w=%d, h=%d\n", */
+               /* canvas_index, cv.addr, cv.width, cv.height); */
+
+               buf = phys_to_virt(cv.addr);
+
+               size = cv.width * cv.height;
+
+               vfs_write(filp, buf, size, &pos);
+               vfs_fsync(filp, 0);
+       }
+       filp_close(filp, NULL);
+       set_fs(old_fs);
+}
+#endif
+
+int vm_fill_this_buffer(struct videobuf_buffer *vb,
+                       struct vm_output_para *para, struct vm_init_s *info)
+
+{
+       int depth = 0;
+       int ret = 0;
+       int canvas_index = -1;
+       int v4l2_format = V4L2_PIX_FMT_YUV444;
+       int magic = 0;
+       int ext_canvas;
+       struct videobuf_buffer buf = {0};
+
+       if (!info)
+               return -1;
+       if (info->vdin_id >= VM_MAX_DEVS) {
+               pr_err("beyond the device array bound .\n");
+               return -1;
+       }
+       /* if (info->isused == false) */
+       /* return -2; */
+#if 0
+       if (!vb)
+               goto exit;
+#else
+       if (!vb) {
+               buf.width = 640;
+               buf.height = 480;
+               v4l2_format =  V4L2_PIX_FMT_YUV444;
+               vb = &buf;
+       }
+
+       if (!vm_device[info->vdin_id]->task_running)
+               return -1;
+#endif
+
+       v4l2_format = para->v4l2_format;
+       magic = para->v4l2_memory;
+       switch (magic) {
+       case   MAGIC_DC_MEM:
+               /* mem = vb->priv; */
+               canvas_config(vm_device[0]->vm_canvas[11],
+                             (dma_addr_t)para->vaddr,
+                             vb->bytesperline, vb->height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_index =  vm_device[0]->vm_canvas[11];
+               depth = (vb->bytesperline << 3) / vb->width;
+               break;
+       case  MAGIC_RE_MEM:
+               if (para->ext_canvas != 0)
+                       canvas_index = get_canvas_index_res(
+                              para->ext_canvas, v4l2_format,
+                              &depth, vb->width,
+                              (para->height == 0) ? vb->height : para->height,
+                              (unsigned int)para->vaddr);
+               else if (info->vdin_id == 0) {
+                       ext_canvas = ((vm_device[0]->vm_canvas[3]) |
+                              (vm_device[0]->vm_canvas[4] << 8) |
+                              (vm_device[0]->vm_canvas[5] << 16));
+                       canvas_index =
+                               get_canvas_index_res(ext_canvas,
+                                    v4l2_format, &depth, vb->width,
+                                    vb->height, (unsigned int)para->vaddr);
+               } else {
+                       ext_canvas = ((vm_device[1]->vm_canvas[0]) |
+                              (vm_device[1]->vm_canvas[1] << 8) |
+                              (vm_device[1]->vm_canvas[2] << 16));
+                       canvas_index =
+                               get_canvas_index_res(ext_canvas,
+                                    v4l2_format, &depth, vb->width,
+                                    vb->height, (unsigned int)para->vaddr);
+               }
+               break;
+       case  MAGIC_SG_MEM:
+       case  MAGIC_VMAL_MEM:
+               if (vm_device[info->vdin_id]->buffer_start &&
+                   vm_device[info->vdin_id]->buffer_size)
+                       canvas_index = get_canvas_index(v4l2_format, &depth);
+               break;
+       default:
+               canvas_index = vm_device[0]->vm_canvas[0];
+               break;
+       }
+       vm_device[info->vdin_id]->output_para.width = vb->width;
+       vm_device[info->vdin_id]->output_para.height = vb->height;
+       vm_device[info->vdin_id]->output_para.bytesperline =
+               (vb->width * depth) >> 3;
+       vm_device[info->vdin_id]->output_para.index = canvas_index;
+       vm_device[info->vdin_id]->output_para.v4l2_format = v4l2_format;
+       vm_device[info->vdin_id]->output_para.v4l2_memory = magic;
+       vm_device[info->vdin_id]->output_para.mirror = para->mirror;
+       vm_device[info->vdin_id]->output_para.zoom = para->zoom;
+       vm_device[info->vdin_id]->output_para.angle = para->angle;
+       vm_device[info->vdin_id]->output_para.vaddr = para->vaddr;
+       vm_device[info->vdin_id]->output_para.ext_canvas =
+               (magic == MAGIC_RE_MEM) ? para->ext_canvas : 0;
+       complete(&vm_device[info->vdin_id]->vb_start_sema);
+       wait_for_completion(&vm_device[info->vdin_id]->vb_done_sema);
+       if (magic == MAGIC_RE_MEM)
+               vm_cache_this_flush((unsigned int)para->vaddr,
+                                   para->bytesperline *
+                                   para->height, info);
+
+       return ret;
+}
+
+/*
+ *for decoder input processing
+ *  1. output window should 1:1 as source frame size
+ *  2. keep the frame ratio
+ *  3. input format should be YUV420 , output format should be YUV444
+ */
+
+int vm_ge2d_pre_process(struct vframe_s *vf,
+                                       struct ge2d_context_s *context,
+                                       struct config_para_ex_s *ge2d_config,
+                                       struct vm_output_para output_para,
+                                       unsigned int index)
+{
+       int ret;
+       int src_top, src_left, src_width, src_height;
+       struct canvas_s cs0, cs1, cs2, cd;
+       int current_mirror = 0;
+       int cur_angle = 0;
+       struct display_frame_s input_frame = {0};
+
+       ret = get_input_frame(&input_frame, vf, output_para.zoom);
+       src_top = input_frame.content_top;
+       src_left = input_frame.content_left;
+       src_width = input_frame.content_width;
+       src_height = input_frame.content_height;
+       if (vm_device[index]->test_zoom) {
+               vm_device[index]->test_zoom = 0;
+               pr_debug("top is %d , left is %d\n",
+                        input_frame.content_top,
+                        input_frame.content_left);
+               pr_debug("width is %d , height is %d\n",
+                        input_frame.content_width,
+                        input_frame.content_height);
+       }
+#ifdef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+       current_mirror = output_para.mirror;
+       if (current_mirror < 0)
+               current_mirror = 0;
+#else
+       current_mirror = camera_mirror_flag;
+#endif
+
+       cur_angle = output_para.angle;
+       if (current_mirror == 1)
+               cur_angle = (360 - cur_angle % 360);
+       else
+               cur_angle = cur_angle % 360;
+
+       /* data operating. */
+       ge2d_config->alu_const_color = 0; /* 0x000000ff; */
+       ge2d_config->bitmask_en  = 0;
+       ge2d_config->src1_gb_alpha = 0;/* 0xff; */
+       ge2d_config->dst_xy_swap = 0;
+
+       canvas_read(vf->canvas0Addr & 0xff, &cs0);
+       canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1);
+       canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2);
+       ge2d_config->src_planes[0].addr = cs0.addr;
+       ge2d_config->src_planes[0].w = cs0.width;
+       ge2d_config->src_planes[0].h = cs0.height;
+       ge2d_config->src_planes[1].addr = cs1.addr;
+       ge2d_config->src_planes[1].w = cs1.width;
+       ge2d_config->src_planes[1].h = cs1.height;
+       ge2d_config->src_planes[2].addr = cs2.addr;
+       ge2d_config->src_planes[2].w = cs2.width;
+       ge2d_config->src_planes[2].h = cs2.height;
+       canvas_read(output_para.index & 0xff, &cd);
+       ge2d_config->dst_planes[0].addr = cd.addr;
+       ge2d_config->dst_planes[0].w = cd.width;
+       ge2d_config->dst_planes[0].h = cd.height;
+       ge2d_config->src_key.key_enable = 0;
+       ge2d_config->src_key.key_mask = 0;
+       ge2d_config->src_key.key_mode = 0;
+       ge2d_config->src_para.canvas_index = vf->canvas0Addr;
+       ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
+       ge2d_config->src_para.format = get_input_format(vf);
+       ge2d_config->src_para.fill_color_en = 0;
+       ge2d_config->src_para.fill_mode = 0;
+       ge2d_config->src_para.x_rev = 0;
+       ge2d_config->src_para.y_rev = 0;
+       ge2d_config->src_para.color = 0xffffffff;
+       ge2d_config->src_para.top = 0;
+       ge2d_config->src_para.left = 0;
+       ge2d_config->src_para.width = vf->width;
+       ge2d_config->src_para.height = vf->height;
+       ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
+       ge2d_config->dst_para.canvas_index = output_para.index & 0xff;
+#ifdef GE2D_NV
+       if ((output_para.v4l2_format != V4L2_PIX_FMT_YUV420)
+           && (output_para.v4l2_format != V4L2_PIX_FMT_YVU420))
+               ge2d_config->dst_para.canvas_index = output_para.index;
+#endif
+       ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
+       ge2d_config->dst_para.format =
+               get_output_format(output_para.v4l2_format) |
+               GE2D_LITTLE_ENDIAN;
+       ge2d_config->dst_para.fill_color_en = 0;
+       ge2d_config->dst_para.fill_mode = 0;
+       ge2d_config->dst_para.x_rev = 0;
+       ge2d_config->dst_para.y_rev = 0;
+       ge2d_config->dst_para.color = 0;
+       ge2d_config->dst_para.top = 0;
+       ge2d_config->dst_para.left = 0;
+       ge2d_config->dst_para.width = output_para.width;
+       ge2d_config->dst_para.height = output_para.height;
+
+       if (current_mirror == 1) {
+               ge2d_config->dst_para.x_rev = 1;
+               ge2d_config->dst_para.y_rev = 0;
+       } else if (current_mirror == 2) {
+               ge2d_config->dst_para.x_rev = 0;
+               ge2d_config->dst_para.y_rev = 1;
+       } else {
+               ge2d_config->dst_para.x_rev = 0;
+               ge2d_config->dst_para.y_rev = 0;
+       }
+
+       if (cur_angle == 90) {
+               ge2d_config->dst_xy_swap = 1;
+               ge2d_config->dst_para.x_rev ^= 1;
+       } else if (cur_angle == 180) {
+               ge2d_config->dst_para.x_rev ^= 1;
+               ge2d_config->dst_para.y_rev ^= 1;
+       } else if (cur_angle == 270) {
+               ge2d_config->dst_xy_swap = 1;
+               ge2d_config->dst_para.y_rev ^= 1;
+       }
+
+       if (ge2d_context_config_ex(context, ge2d_config) < 0) {
+               pr_err("++ge2d configing error.\n");
+               return -1;
+       }
+       stretchblt_noalpha(context, src_left, src_top,
+                          src_width, src_height, 0, 0,
+                          output_para.width, output_para.height);
+
+       /* for cr of  yuv420p or yuv420sp. */
+       if ((output_para.v4l2_format == V4L2_PIX_FMT_YUV420)
+           || (output_para.v4l2_format == V4L2_PIX_FMT_YVU420)) {
+               /* for cb. */
+               canvas_read((output_para.index >> 8) & 0xff, &cd);
+               ge2d_config->dst_planes[0].addr = cd.addr;
+               ge2d_config->dst_planes[0].w = cd.width;
+               ge2d_config->dst_planes[0].h = cd.height;
+               ge2d_config->dst_para.canvas_index =
+                       (output_para.index >> 8) & 0xff;
+#ifndef GE2D_NV
+               ge2d_config->dst_para.format =
+                       GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
+#else
+               ge2d_config->dst_para.format =
+                       GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN;
+#endif
+               ge2d_config->dst_para.width = output_para.width / 2;
+               ge2d_config->dst_para.height = output_para.height / 2;
+               ge2d_config->dst_xy_swap = 0;
+
+               if (current_mirror == 1) {
+                       ge2d_config->dst_para.x_rev = 1;
+                       ge2d_config->dst_para.y_rev = 0;
+               } else if (current_mirror == 2) {
+                       ge2d_config->dst_para.x_rev = 0;
+                       ge2d_config->dst_para.y_rev = 1;
+               } else {
+                       ge2d_config->dst_para.x_rev = 0;
+                       ge2d_config->dst_para.y_rev = 0;
+               }
+
+               if (cur_angle == 90) {
+                       ge2d_config->dst_xy_swap = 1;
+                       ge2d_config->dst_para.x_rev ^= 1;
+               } else if (cur_angle == 180) {
+                       ge2d_config->dst_para.x_rev ^= 1;
+                       ge2d_config->dst_para.y_rev ^= 1;
+               } else if (cur_angle == 270) {
+                       ge2d_config->dst_xy_swap = 1;
+                       ge2d_config->dst_para.y_rev ^= 1;
+               }
+
+               if (ge2d_context_config_ex(context, ge2d_config) < 0) {
+                       pr_err("++ge2d configing error.\n");
+                       return -1;
+               }
+               stretchblt_noalpha(context, src_left, src_top,
+                                  src_width, src_height,
+                                  0, 0, ge2d_config->dst_para.width,
+                                  ge2d_config->dst_para.height);
+       }
+#ifndef GE2D_NV
+       else if (output_para.v4l2_format == V4L2_PIX_FMT_NV12 ||
+                output_para.v4l2_format == V4L2_PIX_FMT_NV21) {
+               canvas_read((output_para.index >> 8) & 0xff, &cd);
+               ge2d_config->dst_planes[0].addr = cd.addr;
+               ge2d_config->dst_planes[0].w = cd.width;
+               ge2d_config->dst_planes[0].h = cd.height;
+               ge2d_config->dst_para.canvas_index =
+                       (output_para.index >> 8) & 0xff;
+               ge2d_config->dst_para.format =
+                       GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
+               ge2d_config->dst_para.width = output_para.width / 2;
+               ge2d_config->dst_para.height = output_para.height / 2;
+               ge2d_config->dst_xy_swap = 0;
+
+               if (current_mirror == 1) {
+                       ge2d_config->dst_para.x_rev = 1;
+                       ge2d_config->dst_para.y_rev = 0;
+               } else if (current_mirror == 2) {
+                       ge2d_config->dst_para.x_rev = 0;
+                       ge2d_config->dst_para.y_rev = 1;
+               } else {
+                       ge2d_config->dst_para.x_rev = 0;
+                       ge2d_config->dst_para.y_rev = 0;
+               }
+
+               if (cur_angle == 90) {
+                       ge2d_config->dst_xy_swap = 1;
+                       ge2d_config->dst_para.x_rev ^= 1;
+               } else if (cur_angle == 180) {
+                       ge2d_config->dst_para.x_rev ^= 1;
+                       ge2d_config->dst_para.y_rev ^= 1;
+               } else if (cur_angle == 270) {
+                       ge2d_config->dst_xy_swap = 1;
+                       ge2d_config->dst_para.y_rev ^= 1;
+               }
+
+               if (ge2d_context_config_ex(context, ge2d_config) < 0) {
+                       pr_err("++ge2d configing error.\n");
+                       return -1;
+               }
+               stretchblt_noalpha(context, src_left, src_top,
+                                  src_width, src_height, 0, 0,
+                                  ge2d_config->dst_para.width,
+                                  ge2d_config->dst_para.height);
+       }
+#endif
+
+       /* for cb of yuv420p or yuv420sp. */
+       if (output_para.v4l2_format == V4L2_PIX_FMT_YUV420 ||
+           output_para.v4l2_format == V4L2_PIX_FMT_YVU420
+#ifndef GE2D_NV
+           || output_para.v4l2_format == V4L2_PIX_FMT_NV12 ||
+           output_para.v4l2_format == V4L2_PIX_FMT_NV21
+#endif
+          ) {
+               canvas_read((output_para.index >> 16) & 0xff, &cd);
+               ge2d_config->dst_planes[0].addr = cd.addr;
+               ge2d_config->dst_planes[0].w = cd.width;
+               ge2d_config->dst_planes[0].h = cd.height;
+               ge2d_config->dst_para.canvas_index =
+                       (output_para.index >> 16) & 0xff;
+#ifndef GE2D_NV
+               ge2d_config->dst_para.format =
+                       GE2D_FORMAT_S8_CR | GE2D_LITTLE_ENDIAN;
+#else
+               ge2d_config->dst_para.format =
+                       GE2D_FORMAT_S8_CB | GE2D_LITTLE_ENDIAN;
+#endif
+               ge2d_config->dst_para.width = output_para.width / 2;
+               ge2d_config->dst_para.height = output_para.height / 2;
+               ge2d_config->dst_xy_swap = 0;
+
+               if (current_mirror == 1) {
+                       ge2d_config->dst_para.x_rev = 1;
+                       ge2d_config->dst_para.y_rev = 0;
+               } else if (current_mirror == 2) {
+                       ge2d_config->dst_para.x_rev = 0;
+                       ge2d_config->dst_para.y_rev = 1;
+               } else {
+                       ge2d_config->dst_para.x_rev = 0;
+                       ge2d_config->dst_para.y_rev = 0;
+               }
+
+               if (cur_angle == 90) {
+                       ge2d_config->dst_xy_swap = 1;
+                       ge2d_config->dst_para.x_rev ^= 1;
+               } else if (cur_angle == 180) {
+                       ge2d_config->dst_para.x_rev ^= 1;
+                       ge2d_config->dst_para.y_rev ^= 1;
+               } else if (cur_angle == 270) {
+                       ge2d_config->dst_xy_swap = 1;
+                       ge2d_config->dst_para.y_rev ^= 1;
+               }
+
+               if (ge2d_context_config_ex(context, ge2d_config) < 0) {
+                       pr_err("++ge2d configing error.\n");
+                       return -1;
+               }
+               stretchblt_noalpha(context, src_left,
+                                  src_top, src_width, src_height,
+                                  0, 0, ge2d_config->dst_para.width,
+                                  ge2d_config->dst_para.height);
+       }
+       return output_para.index;
+}
+
+int vm_sw_post_process(int canvas, uintptr_t addr, unsigned int index)
+{
+       int poss = 0, posd = 0;
+       int i = 0;
+       void __iomem *buffer_y_start;
+       void __iomem *buffer_u_start;
+       void __iomem *buffer_v_start = 0;
+       struct io_mapping *mapping_wc;
+       int offset = 0;
+       struct canvas_s canvas_work_y;
+       struct canvas_s canvas_work_u;
+       struct canvas_s canvas_work_v;
+       struct vm_output_para output_para = vm_device[index]->output_para;
+
+       if (!addr)
+               return -1;
+       mapping_wc = io_mapping_create_wc(vm_device[index]->buffer_start,
+                                         vm_device[index]->buffer_size);
+       if (!mapping_wc)
+               return -1;
+       canvas_read(canvas & 0xff, &canvas_work_y);
+       offset = 0;
+       buffer_y_start = io_mapping_map_atomic_wc(mapping_wc, offset);
+       if (buffer_y_start == NULL) {
+               pr_err(" vm.postprocess:mapping buffer error\n");
+               io_mapping_free(mapping_wc);
+               return -1;
+       }
+       if (output_para.v4l2_format == V4L2_PIX_FMT_BGR24 ||
+           output_para.v4l2_format == V4L2_PIX_FMT_RGB24 ||
+           output_para.v4l2_format == V4L2_PIX_FMT_RGB565X) {
+               for (i = 0; i < output_para.height; i++) {
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_y_start + posd),
+                              output_para.bytesperline);
+                       poss += output_para.bytesperline;
+                       posd += canvas_work_y.width;
+               }
+               io_mapping_unmap_atomic(buffer_y_start);
+
+       } else if (output_para.v4l2_format == V4L2_PIX_FMT_NV12 ||
+                  output_para.v4l2_format == V4L2_PIX_FMT_NV21) {
+#ifdef GE2D_NV
+               unsigned int uv_width = output_para.width;
+               unsigned int uv_height = output_para.height >> 1;
+
+               posd = 0;
+               for (i = output_para.height; i > 0; i--) { /* copy y */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_y_start + posd),
+                              output_para.width);
+                       poss += output_para.width;
+                       posd += canvas_work_y.width;
+               }
+               io_mapping_unmap_atomic(buffer_y_start);
+
+               posd = 0;
+               canvas_read((canvas >> 8) & 0xff, &canvas_work_u);
+               offset = canvas_work_u.addr - canvas_work_y.addr;
+               buffer_u_start = io_mapping_map_atomic_wc(mapping_wc, offset);
+               for (i = uv_height; i > 0; i--) { /* copy uv */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_u_start + posd), uv_width);
+                       poss += uv_width;
+                       posd += canvas_work_u.width;
+               }
+
+               io_mapping_unmap_atomic(buffer_u_start);
+#else
+               char *dst_buff = NULL;
+               char *src_buff = NULL;
+               char *src2_buff = NULL;
+
+               canvas_read((canvas >> 8) & 0xff, &canvas_work_u);
+               poss = posd = 0;
+               for (i = 0; i < output_para.height; i += 2) { /* copy y */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_y_start + posd),
+                              output_para.width);
+                       poss += output_para.width;
+                       posd += canvas_work_y.width;
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_y_start + posd),
+                              output_para.width);
+                       poss += output_para.width;
+                       posd += canvas_work_y.width;
+               }
+               io_mapping_unmap_atomic(buffer_y_start);
+
+               posd = 0;
+               canvas_read((canvas >> 16) & 0xff, &canvas_work_v);
+               offset = canvas_work_u.addr - canvas_work_y.addr;
+               buffer_u_start = io_mapping_map_atomic_wc(mapping_wc, offset);
+               offset = canvas_work_v.addr - canvas_work_y.addr;
+               buffer_v_start = io_mapping_map_atomic_wc(mapping_wc, offset);
+
+               dst_buff = (char *)addr +
+                          output_para.width * output_para.height;
+               src_buff = (char *)buffer_u_start;
+               src2_buff = (char *)buffer_v_start;
+               if (output_para.v4l2_format == V4L2_PIX_FMT_NV12) {
+                       for (i = 0 ; i < output_para.height / 2; i++) {
+                               interleave_uv(src_buff, src2_buff,
+                                             dst_buff, output_para.width / 2);
+                               src_buff +=  canvas_work_u.width;
+                               src2_buff +=    canvas_work_v.width;
+                               dst_buff += output_para.width;
+                       }
+               } else {
+                       for (i = 0 ; i < output_para.height / 2; i++) {
+                               interleave_uv(src2_buff, src_buff,
+                                             dst_buff, output_para.width / 2);
+                               src_buff +=  canvas_work_u.width;
+                               src2_buff +=    canvas_work_v.width;
+                               dst_buff += output_para.width;
+                       }
+               }
+
+
+               io_mapping_unmap_atomic(buffer_u_start);
+               io_mapping_unmap_atomic(buffer_v_start);
+#endif
+       } else if ((output_para.v4l2_format == V4L2_PIX_FMT_YUV420)
+                  || (output_para.v4l2_format == V4L2_PIX_FMT_YVU420)) {
+               int uv_width = output_para.width >> 1;
+               int uv_height = output_para.height >> 1;
+
+               posd = 0;
+               for (i = output_para.height; i > 0; i--) { /* copy y */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_y_start + posd),
+                              output_para.width);
+                       poss += output_para.width;
+                       posd += canvas_work_y.width;
+               }
+               io_mapping_unmap_atomic(buffer_y_start);
+
+               posd = 0;
+               canvas_read((canvas >> 8) & 0xff, &canvas_work_u);
+               offset = canvas_work_u.addr - canvas_work_y.addr;
+               buffer_u_start = io_mapping_map_atomic_wc(mapping_wc, offset);
+
+               canvas_read((canvas >> 16) & 0xff, &canvas_work_v);
+               offset = canvas_work_v.addr - canvas_work_y.addr;
+               buffer_v_start = io_mapping_map_atomic_wc(mapping_wc, offset);
+
+#ifndef GE2D_NV
+               if (output_para.v4l2_format == V4L2_PIX_FMT_YUV420)
+#else
+               if (output_para.v4l2_format == V4L2_PIX_FMT_YVU420) {
+#endif
+                       for (i = uv_height; i > 0; i--) { /* copy y */
+                               memcpy((void *)(addr + poss),
+                                      (void *)(buffer_u_start + posd),
+                                      uv_width);
+                               poss += uv_width;
+                               posd += canvas_work_u.width;
+                       }
+               posd = 0;
+               for (i = uv_height; i > 0; i--) { /* copy y */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_v_start + posd),
+                              uv_width);
+                       poss += uv_width;
+                       posd += canvas_work_v.width;
+               }
+       } else {
+               for (i = uv_height; i > 0; i--) { /* copy v */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_v_start + posd),
+                              uv_width);
+                       poss += uv_width;
+                       posd += canvas_work_v.width;
+               }
+               posd = 0;
+               for (i = uv_height; i > 0; i--) { /* copy u */
+                       memcpy((void *)(addr + poss),
+                              (void *)(buffer_u_start + posd),
+                              uv_width);
+                       poss += uv_width;
+                       posd += canvas_work_u.width;
+               }
+       }
+       io_mapping_unmap_atomic(buffer_u_start);
+       io_mapping_unmap_atomic(buffer_v_start);
+}
+
+       if (mapping_wc)
+               io_mapping_free(mapping_wc);
+
+       return 0;
+}
+
+static struct task_struct *simulate_task_fd;
+
+static bool is_vf_available(unsigned int vdin_id)
+{
+       bool ret = ((local_vf_peek(vdin_id) != NULL) ||
+                       (!vm_device[vdin_id]->task_running));
+       return ret;
+}
+
+/* static int reset_frame = 1; */
+static int vm_task(void *data)
+{
+       int ret = 0;
+       struct vframe_s *vf;
+       int src_canvas;
+       struct vm_device_s *devp = (struct vm_device_s *) data;
+       struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
+       struct ge2d_context_s *context = create_ge2d_work_queue();
+       struct config_para_ex_s ge2d_config;
+
+#ifdef CONFIG_AMLCAP_LOG_TIME_USEFORFRAMES
+       struct timeval start;
+       struct timeval end;
+       unsigned long time_use = 0;
+#endif
+       memset(&ge2d_config, 0, sizeof(struct config_para_ex_s));
+       sched_setscheduler(current, SCHED_FIFO, &param);
+       allow_signal(SIGTERM);
+       while (1) {
+               ret = wait_for_completion_interruptible(
+                             &devp->vb_start_sema);
+
+               if (kthread_should_stop()) {
+                       complete(&devp->vb_done_sema);
+                       break;
+               }
+
+               /* wait for frame from 656 provider until 500ms runs out */
+               wait_event_interruptible_timeout(devp->frame_ready,
+                                               is_vf_available(devp->index),
+                                               msecs_to_jiffies(2000));
+
+               if (!devp->task_running) {
+                       ret = -1;
+                       goto vm_exit;
+               }
+
+               /* start to convert frame. */
+#ifdef CONFIG_AMLCAP_LOG_TIME_USEFORFRAMES
+               do_gettimeofday(&start);
+#endif
+               vf = local_vf_get(devp->index);
+
+               if (vf) {
+                       src_canvas = vf->canvas0Addr;
+
+                       /* step1 convert 422 format to other format.*/
+                       if (is_need_ge2d_pre_process(devp->output_para))
+                               src_canvas = vm_ge2d_pre_process(vf, context,
+                                        &ge2d_config, devp->output_para,
+                                        devp->index);
+#if 0
+                       if (devp->dump == 2) {
+                               vm_dump_mem(devp->dump_path,
+                           (void *)output_para.vaddr, &output_para);
+                               devp->dump = 0;
+                       }
+#endif
+                       local_vf_put(vf, devp->index);
+#ifdef CONFIG_AMLCAP_LOG_TIME_USEFORFRAMES
+                       do_gettimeofday(&end);
+                       time_use = (end.tv_sec - start.tv_sec) * 1000 +
+                                  (end.tv_usec - start.tv_usec) / 1000;
+                       pr_debug("step 1, ge2d use: %ldms\n", time_use);
+                       do_gettimeofday(&start);
+#endif
+
+                       /* step2 copy to user memory. */
+
+                       if (is_need_sw_post_process(devp->output_para))
+                               vm_sw_post_process(src_canvas,
+                                  devp->output_para.vaddr, devp->index);
+
+#ifdef CONFIG_AMLCAP_LOG_TIME_USEFORFRAMES
+                       do_gettimeofday(&end);
+                       time_use = (end.tv_sec - start.tv_sec) * 1000 +
+                                  (end.tv_usec - start.tv_usec) / 1000;
+                       pr_debug("step 2, memcpy use: %ldms\n", time_use);
+#endif
+               }
+               if (kthread_should_stop()) {
+                       complete(&devp->vb_done_sema);
+                       break;
+               }
+               complete(&devp->vb_done_sema);
+       }
+vm_exit:
+       destroy_ge2d_work_queue(context);
+       while (!kthread_should_stop()) {
+               /*may not call stop, wait..
+                *it is killed by SIGTERM,eixt on
+                *down_interruptible.
+                *if not call stop,this thread
+                *may on do_exit and
+                *kthread_stop may not work good;
+                */
+               msleep(20);/*default 10ms*/
+       }
+       return ret;
+}
+
+/*simulate v4l2 device to request*/
+/*filling buffer,only for test use*/
+static int simulate_task(void *data)
+{
+       while (1) {
+               msleep(50);
+               pr_debug("simulate succeed\n");
+       }
+       return 0;
+}
+
+/*
+ ***********************************************
+ *
+ *   init functions.
+ *
+ ***********************************************
+ */
+
+int vm_buffer_init(struct vm_device_s *vdevp)
+{
+       int i, j;
+       u32 canvas_width, canvas_height;
+       u32 decbuf_size;
+       resource_size_t buf_start;
+       unsigned int buf_size;
+       int buf_num = 0;
+       int local_pool_size = 0;
+
+       init_completion(&vdevp->vb_start_sema);
+       init_completion(&vdevp->vb_done_sema);
+
+       buf_start = vdevp->buffer_start;
+       buf_size = vdevp->buffer_size;
+
+       if (vdevp->index == 0) {
+               for (j = 0; j < MAX_CANVAS_INDEX; j++) {
+                       memset(&(vdevp->vm_canvas[j]), -1, sizeof(int));
+                       vdevp->vm_canvas[j] =
+                               canvas_pool_map_alloc_canvas("vm0");
+                       if (vdevp->vm_canvas[j] < 0) {
+                               pr_err("alloc vm0_canvas %d failed\n", j);
+                               return -1;
+                       }
+               }
+       } else {
+               for (j = 0; j < MAX_CANVAS_INDEX; j++) {
+                       memset(&(vdevp->vm_canvas[j]), -1, sizeof(int));
+                       vdevp->vm_canvas[j] =
+                               canvas_pool_map_alloc_canvas("vm1");
+                       if (vdevp->vm_canvas[j] < 0) {
+                               pr_err("alloc vm1_canvas %d failed\n", j);
+                               return -1;
+                       }
+               }
+       }
+
+       if (!buf_start || !buf_size)
+               goto exit;
+
+       for (i = 0; i < ARRAY_SIZE(vmdecbuf_size); i++) {
+               if (buf_size >= vmdecbuf_size[i])
+                       break;
+       }
+       if (i == ARRAY_SIZE(vmdecbuf_size)) {
+               pr_debug("vmbuf size=%d less than the smallest vmbuf size%d\n",
+                        buf_size, vmdecbuf_size[i - 1]);
+               return -1;
+       }
+
+       canvas_width = canvas_config_wh[i].width;/* 1920; */
+       canvas_height = canvas_config_wh[i].height;/* 1200; */
+       decbuf_size = vmdecbuf_size[i];/* 0x700000; */
+       buf_num  = buf_size / decbuf_size;
+
+       if (buf_num > 0)
+               local_pool_size   = 1;
+       else {
+               local_pool_size = 0;
+               pr_debug("need at least one buffer to handle 1920*1080 data.\n");
+       }
+
+       for (i = 0; i < local_pool_size; i++) {
+               canvas_config((vdevp->vm_canvas[0] + i),
+                             (unsigned long)(buf_start + i * decbuf_size),
+                             canvas_width * 2, canvas_height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config((vdevp->vm_canvas[2] + i),
+                             (unsigned long)(buf_start + i * decbuf_size),
+                             canvas_width * 3, canvas_height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config((vdevp->vm_canvas[4] + i),
+                             (unsigned long)(buf_start + i * decbuf_size / 2),
+                             canvas_width, canvas_height,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config(vdevp->vm_canvas[6] + i,
+                             (unsigned long)(buf_start +
+                                             (i + 1)*decbuf_size / 2),
+                             canvas_width, canvas_height / 2,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+
+               canvas_config((vdevp->vm_canvas[8] + i),
+                             (unsigned long)(buf_start +
+                                             (i + 1)*decbuf_size / 2),
+                             canvas_width / 2, canvas_height / 2,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+               canvas_config((vdevp->vm_canvas[10] + i),
+                             (unsigned long)(buf_start +
+                                             (i + 3)*decbuf_size / 4),
+                             canvas_width / 2, canvas_height / 2,
+                             CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+               vfbuf_use[i] = 0;
+#endif
+       }
+
+exit:
+       return 0;
+
+}
+
+int start_vm_task(struct vm_device_s *vdevp)
+{
+       /* init the device. */
+       vm_local_init();
+       if (!vdevp->task) {
+               vdevp->task = kthread_create(vm_task, vdevp, vdevp->name);
+               if (IS_ERR(vdevp->task)) {
+                       pr_err("thread creating error.\n");
+                       return -1;
+               }
+               init_waitqueue_head(&vdevp->frame_ready);
+               wake_up_process(vdevp->task);
+       }
+       vdevp->task_running = 1;
+       return 0;
+}
+
+int start_simulate_task(void)
+{
+       if (!simulate_task_fd) {
+               simulate_task_fd = kthread_create(simulate_task, 0, "vm");
+               if (IS_ERR(simulate_task_fd)) {
+                       pr_err("thread creating error.\n");
+                       return -1;
+               }
+               wake_up_process(simulate_task_fd);
+       }
+       return 0;
+}
+
+
+void stop_vm_task(struct vm_device_s *vdevp)
+{
+       if (vdevp->task) {
+               vdevp->task_running = 0;
+               send_sig(SIGTERM, vdevp->task, 1);
+               complete(&vdevp->vb_start_sema);
+               wake_up_interruptible(&vdevp->frame_ready);
+               kthread_stop(vdevp->task);
+               vdevp->task = NULL;
+       }
+       vm_local_init();
+}
+
+
+/*
+ **********************************************************************
+ *
+ * global status.
+ *
+ **********************************************************************
+ */
+
+static int vm_enable_flag;
+
+int get_vm_status(void)
+{
+       return vm_enable_flag;
+}
+
+void set_vm_status(int flag)
+{
+       if (flag >= 0)
+               vm_enable_flag = flag;
+       else
+               vm_enable_flag = 0;
+}
+
+/*
+ **********************************************************************
+ *
+ * file op section.
+ *
+ **********************************************************************
+ */
+
+void unset_vm_buf_res(struct vm_init_s *info)
+{
+       info->buffer_start = 0;
+}
+
+static void vm_cache_this_flush(unsigned int buf_start, unsigned int buf_size,
+                               struct vm_init_s *info)
+{
+       struct vm_device_s *devp = vm_device[info->vdin_id];
+
+       if (devp->dev) {
+               if ((buf_start >= info->buffer_start) &&
+                   ((buf_start + buf_size) <= (info->buffer_start +
+                                               info->vm_buf_size)))
+                       dma_sync_single_for_cpu(devp->dev,
+                               buf_start, buf_size, DMA_FROM_DEVICE);
+       }
+}
+
+static int vm_open(struct inode *inode, struct file *file)
+{
+       struct ge2d_context_s *context = NULL;
+
+       pr_info("open one vm device\n");
+       file->private_data = context;
+       /* vm_device.open_count++; */
+       return 0;
+}
+
+static long vm_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
+{
+       int  ret = 0;
+       struct ge2d_context_s *context;
+       void  __user *argp;
+
+       context = (struct ge2d_context_s *)filp->private_data;
+       argp = (void __user *)args;
+       switch (cmd) {
+       case VM_IOC_2OSD0:
+               break;
+       case VM_IOC_ENABLE_PP:
+               break;
+       case VM_IOC_CONFIG_FRAME:
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return ret;
+}
+
+static int vm_release(struct inode *inode, struct file *file)
+{
+       struct ge2d_context_s *context =
+               (struct ge2d_context_s *)file->private_data;
+
+       if (context && (destroy_ge2d_work_queue(context) == 0)) {
+               /* vm_device.open_count--; */
+               return 0;
+       }
+       pr_info("release one vm device\n");
+       return -1;
+}
+
+/*
+ **********************************************************************
+ *
+ * file op init section.
+ *
+ **********************************************************************
+ */
+
+static const struct file_operations vm_fops = {
+       .owner = THIS_MODULE,
+       .open = vm_open,
+       .unlocked_ioctl = vm_ioctl,
+       .release = vm_release,
+};
+
+static ssize_t vm_attr_show(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       ssize_t len = 0;
+       struct vm_device_s *devp;
+
+       devp = dev_get_drvdata(dev);
+       if (devp->task_running == 0) {
+               len += sprintf(buf + len, "vm does not start\n");
+               return len;
+       }
+
+       len += sprintf((char *)buf + len, "vm parameters below\n");
+
+       return len;
+}
+
+static ssize_t vm_attr_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t len)
+{
+       struct vm_device_s *devp;
+       unsigned int n = 0;
+       char *buf_orig, *ps, *token;
+       char *parm[6] = {NULL};
+
+       if (!buf)
+               return len;
+
+       buf_orig = kstrdup(buf, GFP_KERNEL);
+       /* printk(KERN_INFO "input cmd : %s",buf_orig); */
+       devp = dev_get_drvdata(dev);
+       if (devp->task_running == 0) {
+               len += sprintf((char *)buf + len, "vm does not start\n");
+               return len;
+       }
+
+       ps = buf_orig;
+       while (1) {
+               if (n >= ARRAY_SIZE(parm)) {
+                       pr_err("parm array overflow.\n");
+#if 0
+                       pr_err("n=%d,ARRAY_SIZE(parm)=%d\n",
+                              n, ARRAY_SIZE(parm));
+#endif
+                       return len;
+               }
+               token = strsep(&ps, "\n");
+               if (token == NULL)
+                       break;
+               if (*token == '\0')
+                       continue;
+               parm[n++] = token;
+       }
+
+       if (strcmp(parm[0], "before") == 0) {
+               devp->dump = 1;
+               devp->dump_path = parm[1];
+               pr_debug("this not support\n");
+       } else if (strcmp(parm[0], "after") == 0) {
+               devp->dump = 2;
+               devp->dump_path = parm[1];
+               pr_debug("after ge2d processed, store to %s\n", parm[1]);
+       }
+
+       kfree(buf_orig);
+       return len;
+}
+
+static DEVICE_ATTR(dump, 0664, vm_attr_show, vm_attr_store);
+
+static int vm_add_cdev(struct cdev *cdevp,
+                      const struct file_operations *fops,
+                      int minor)
+{
+       int ret;
+       dev_t devno = MKDEV(MAJOR(vm_devno), minor);
+
+       cdev_init(cdevp, fops);
+       cdevp->owner = THIS_MODULE;
+       ret = cdev_add(cdevp, devno, 1);
+       return ret;
+}
+
+int init_vm_device(struct vm_device_s *vdevp, struct platform_device *pdev)
+{
+       int  ret = 0;
+
+       ret = vm_add_cdev(&vdevp->cdev, &vm_fops, vdevp->index);
+       if (ret) {
+               pr_err("%s: failed to add cdev. !\n", __func__);
+               goto fail_add_cdev;
+       }
+       vdevp->dev = device_create(vm_clsp, &pdev->dev, MKDEV(MAJOR(vm_devno),
+                                  vdevp->index),
+                                  NULL, "%s%d", VM_DEV_NAME, vdevp->index);
+       if (IS_ERR(vdevp->dev)) {
+               pr_err("%s: failed to create device. !\n", __func__);
+               ret = PTR_ERR(vdevp->dev);
+               goto fail_create_device;
+       }
+       ret = device_create_file(vdevp->dev, &dev_attr_dump);
+       if (ret < 0) {
+               pr_err("%s: fail to create vdin attribute files.\n", __func__);
+               goto fail_create_dev_file;
+       }
+
+       dev_set_drvdata(vdevp->dev, vdevp);
+       platform_set_drvdata(pdev, vdevp);
+
+       /* if (vm_buffer_init(vdevp) < 0) */
+       /* goto unregister_dev; */
+#ifndef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
+       vf_provider_init(&vm_vf_prov, PROVIDER_NAME, &vm_vf_provider, NULL);
+#endif
+       /* vf_reg_provider(&vm_vf_prov); */
+       vdevp->task = NULL;
+       vdevp->task_running = 0;
+       memset(&vdevp->output_para, 0, sizeof(struct vm_output_para));
+       sprintf(vdevp->name, "%s%d", RECEIVER_NAME, vdevp->index);
+       sprintf(vdevp->vf_provider_name, "%s%d", "vdin", vdevp->index);
+
+       snprintf(vdevp->vfm_map_chain, VM_MAP_NAME_SIZE,
+                               "%s %s", vdevp->vf_provider_name,
+                               vdevp->name);
+       snprintf(vdevp->vfm_map_id, VM_MAP_NAME_SIZE,
+                               "vm-map-%d", vdevp->index);
+       if (vfm_map_add(vdevp->vfm_map_id,
+               vdevp->vfm_map_chain) < 0) {
+               pr_err("vm pipeline map creation failed %s.\n",
+                       vdevp->vfm_map_id);
+               goto fail_create_dev_file;
+       }
+
+       vf_receiver_init(&vdevp->vm_vf_recv, vdevp->name,
+                       &vm_vf_receiver, vdevp);
+
+       vf_reg_receiver(&vdevp->vm_vf_recv);
+       return 0;
+
+       /* unregister_dev: */
+fail_create_dev_file:
+       device_destroy(vm_clsp, MKDEV(MAJOR(vm_devno), vdevp->index));
+fail_create_device:
+       cdev_del(&vdevp->cdev);
+fail_add_cdev:
+       kfree(vdevp);
+       return ret;
+
+}
+
+int uninit_vm_device(struct platform_device *plat_dev)
+{
+       struct vm_device_s *vdevp;
+
+       vdevp = platform_get_drvdata(plat_dev);
+       /* stop_vm_task(vdevp); */
+       device_remove_file(vdevp->dev, &dev_attr_dump);
+       device_destroy(vm_clsp, MKDEV(MAJOR(vm_devno), vdevp->index));
+       cdev_del(&vdevp->cdev);
+       vm_device[vdevp->index] = NULL;
+
+       /* free drvdata */
+       dev_set_drvdata(vdevp->dev, NULL);
+       platform_set_drvdata(plat_dev, NULL);
+       kfree(vdevp);
+       return 0;
+}
+
+int vm_init_resource(size_t size, struct vm_init_s *info)
+{
+       struct vm_device_s *devp;
+#ifdef CONFIG_CMA
+       devp = vm_device[info->vdin_id];
+       if (size == 0)
+               return -1;
+       if (info->vm_pages && info->vm_buf_size != 0) {
+
+               dma_release_from_contiguous(&devp->pdev->dev,
+                                           info->vm_pages,
+                                           info->vm_buf_size / PAGE_SIZE);
+       }
+       info->vm_pages = dma_alloc_from_contiguous(&devp->pdev->dev,
+                        size / PAGE_SIZE, 0);
+       if (info->vm_pages) {
+               dma_addr_t phys;
+
+               phys = page_to_phys(info->vm_pages);
+               info->buffer_start = phys;
+               info->vm_buf_size = size;
+               if (info->bt_path_count == 1) {
+                       if (info->vdin_id == 0)
+                               info->isused = true;
+                       else
+                               info->isused = false;
+               } else {
+                       info->isused = true;
+               }
+               info->mem_alloc_succeed = true;
+               return 0;
+       }
+
+       info->mem_alloc_succeed = false;
+       pr_err("CMA failed to allocate dma buffer\n");
+       return -ENOMEM;
+#else
+       if (size == 0)
+               return -1;
+       info->buffer_start = vm_device[info->vdin_id]->buffer_start;
+       info->vm_buf_size = vm_device[info->vdin_id]->buffer_size;
+       info->mem_alloc_succeed = true;
+       info->isused = true;
+       return 0;
+#endif
+}
+EXPORT_SYMBOL(vm_init_resource);
+
+void vm_deinit_resource(struct vm_init_s *info)
+{
+#ifdef CONFIG_CMA
+       struct vm_device_s *devp;
+
+       devp = vm_device[info->vdin_id];
+       if (info->vm_buf_size == 0) {
+               pr_warn("vm buf size equals 0\n");
+               return;
+       }
+       unset_vm_buf_res(info);
+
+       if (info->vm_pages) {
+               dma_release_from_contiguous(&devp->pdev->dev,
+                                           info->vm_pages,
+                                           info->vm_buf_size / PAGE_SIZE);
+               info->vm_buf_size = 0;
+               info->vm_pages = NULL;
+               info->isused = false;
+               info->mem_alloc_succeed = false;
+       }
+#else
+       if (info->vm_buf_size) {
+               info->buffer_start = 0;
+               info->vm_buf_size = 0;
+               info->isused = false;
+               info->mem_alloc_succeed = false;
+       }
+#endif
+}
+EXPORT_SYMBOL(vm_deinit_resource);
+
+
+/*******************************************************************
+ *
+ * interface for Linux driver
+ *
+ * ******************************************************************/
+
+static int vm_mem_device_init(struct reserved_mem *rmem, struct device *dev)
+{
+       struct platform_device *pdev = container_of(dev,
+                                       struct platform_device, dev);
+       struct vm_device_s *vdevp = platform_get_drvdata(pdev);
+       unsigned long mem_start, mem_end;
+
+       vdevp->buffer_start = rmem->base;
+       vdevp->buffer_size = rmem->size;
+       mem_start = rmem->base;
+       mem_end = rmem->base + rmem->size - 1;
+       pr_info("init vm memsource %lx->%lx\n", mem_start, mem_end);
+       return 0;
+}
+
+static const struct reserved_mem_ops rmem_vm_ops = {
+       .device_init = vm_mem_device_init,
+};
+
+static int __init vm_mem_setup(struct reserved_mem *rmem)
+{
+       rmem->ops = &rmem_vm_ops;
+       pr_info("vm share mem setup\n");
+       return 0;
+}
+
+/* MODULE_AMLOG(AMLOG_DEFAULT_LEVEL, 0xff, LOG_LEVEL_DESC, LOG_MASK_DESC); */
+
+
+/* for driver. */
+static int vm_driver_probe(struct platform_device *pdev)
+{
+       int idx;
+       int ret;
+       struct vm_device_s *vdevp;
+
+       pr_info("vm memory init\n");
+       /* malloc vdev */
+       vdevp = kmalloc(sizeof(struct vm_device_s), GFP_KERNEL);
+       if (!vdevp)
+               return -ENOMEM;
+
+       memset(vdevp, 0, sizeof(struct vm_device_s));
+
+       if (pdev->dev.of_node) {
+               ret = of_property_read_u32(pdev->dev.of_node,
+                                          "vm_id", &(vdevp->index));
+               if (ret)
+                       pr_err("don't find vm id.\n");
+       }
+       vm_device[vdevp->index] = vdevp;
+       vdevp->pdev = pdev;
+       platform_set_drvdata(pdev, vdevp);
+       vm_buffer_init(vdevp);
+       ret = init_vm_device(vdevp, pdev);
+       if (ret != 0)
+               return ret;
+       idx = of_reserved_mem_device_init(&pdev->dev);
+       if (idx == 0)
+               pr_info("vm probe done\n");
+       else
+               pr_info("malloc reserved memory failed !\n");
+
+       /* init_vm_device(vdevp, pdev); */
+       return 0;
+}
+
+static int vm_drv_remove(struct platform_device *plat_dev)
+{
+       int i;
+       struct vm_device_s *vdevp;
+
+       vdevp = platform_get_drvdata(plat_dev);
+
+       for (i = 0; i < MAX_CANVAS_INDEX; i++) {
+               if ((vdevp != NULL) &&
+                       (vdevp->vm_canvas[i] >= 0)) {
+                       canvas_pool_map_free_canvas(
+                          vdevp->vm_canvas[i]);
+                       memset(&(vdevp->vm_canvas[i]),
+                               -1, sizeof(int));
+               }
+       }
+
+       if (vdevp->vfm_map_id[0]) {
+               vfm_map_remove(vdevp->vfm_map_id);
+               vdevp->vfm_map_id[0] = 0;
+       }
+
+       uninit_vm_device(plat_dev);
+       return 0;
+}
+
+static const struct of_device_id amlogic_vm_dt_match[] = {
+       {
+               .compatible = "amlogic, vm",
+       },
+       {},
+};
+
+/* general interface for a linux driver .*/
+static struct platform_driver vm_drv = {
+       .probe  = vm_driver_probe,
+       .remove = vm_drv_remove,
+       .driver = {
+               .name = "vm",
+               .owner = THIS_MODULE,
+               .of_match_table = amlogic_vm_dt_match,
+       }
+};
+
+static int __init
+vm_init_module(void)
+{
+       int ret = 0;
+
+       pr_info("vm_init .\n");
+       ret = alloc_chrdev_region(&vm_devno, 0, VM_MAX_DEVS, VM_DEV_NAME);
+       if (ret < 0) {
+               pr_err("%s: failed to allocate major number\n", __func__);
+               goto fail_alloc_cdev_region;
+       }
+       vm_clsp = class_create(THIS_MODULE, VM_CLS_NAME);
+       if (IS_ERR(vm_clsp)) {
+               ret = PTR_ERR(vm_clsp);
+               pr_err("%s: failed to create class\n", __func__);
+               goto fail_class_create;
+       }
+       ret = platform_driver_register(&vm_drv);
+       if (ret) {
+               pr_err("Failed to register vm driver (error=%d\n",
+                      ret);
+               goto fail_pdrv_register;
+       }
+       return 0;
+
+fail_pdrv_register:
+       class_destroy(vm_clsp);
+fail_class_create:
+       unregister_chrdev_region(vm_devno, VM_MAX_DEVS);
+fail_alloc_cdev_region:
+       return ret;
+}
+
+static void __exit
+vm_remove_module(void)
+{
+       /* class_remove_file(vm_clsp, &class_attr_dump); */
+       class_destroy(vm_clsp);
+       unregister_chrdev_region(vm_devno, VM_MAX_DEVS);
+       platform_driver_unregister(&vm_drv);
+       pr_info("vm module removed.\n");
+}
+
+module_init(vm_init_module);
+module_exit(vm_remove_module);
+RESERVEDMEM_OF_DECLARE(vm, "amlogic, vm_memory", vm_mem_setup);
+
+MODULE_DESCRIPTION("Amlogic Video Input Manager");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Zheng <simon.zheng@amlogic.com>");
diff --git a/drivers/amlogic/media/camera/common/vm.h b/drivers/amlogic/media/camera/common/vm.h
new file mode 100644 (file)
index 0000000..50305fc
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * drivers/amlogic/media/camera/common/vm.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 _VM_INCLUDE__
+#define _VM_INCLUDE__
+
+#include <linux/interrupt.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/fb.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/sysfs.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/io-mapping.h>
+#include <linux/wait.h>
+#include <linux/semaphore.h>
+#include <linux/cdev.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/camera/aml_cam_info.h>
+#include <linux/amlogic/media/camera/vmapi.h>
+
+/*************************************
+ **
+ **    macro define
+ **
+ *************************************/
+
+#define VM_IOC_MAGIC  'P'
+#define VM_IOC_2OSD0           _IOW(VM_IOC_MAGIC, 0x00, unsigned int)
+#define VM_IOC_ENABLE_PP _IOW(VM_IOC_MAGIC, 0X01, unsigned int)
+#define VM_IOC_CONFIG_FRAME  _IOW(VM_IOC_MAGIC, 0X02, unsigned int)
+#define MAX_CANVAS_INDEX 12
+
+#define VM_MAP_NAME_SIZE 100
+#define VM_PROVIDER_NAME_SIZE 10
+
+struct vm_device_s {
+       unsigned int  index;
+       char name[20];
+       struct platform_device *pdev;
+       int dump;
+       char *dump_path;
+       unsigned int open_count;
+       int major;
+       unsigned int dbg_enable;
+       /* struct class *cla; */
+       struct cdev     cdev;
+       struct device *dev;
+       resource_size_t buffer_start;
+       unsigned int buffer_size;
+#ifdef CONFIG_CMA
+       ulong cma_pool_size;
+#endif
+       struct vframe_receiver_s vm_vf_recv;
+       struct task_struct *task;
+       wait_queue_head_t frame_ready;
+       int task_running;
+       int vm_skip_count;
+       int test_zoom;
+       struct vm_output_para output_para;
+       struct completion vb_start_sema;
+       struct completion vb_done_sema;
+       char vf_provider_name[VM_PROVIDER_NAME_SIZE];
+       char vfm_map_id[VM_MAP_NAME_SIZE];
+       char vfm_map_chain[VM_MAP_NAME_SIZE];
+       int vm_canvas[MAX_CANVAS_INDEX];
+};
+
+struct display_frame_s {
+       int frame_top;
+       int frame_left;
+       int frame_width;
+       int frame_height;
+       int content_top;
+       int content_left;
+       int content_width;
+       int content_height;
+};
+
+int start_vm_task(struct vm_device_s *vdevp);
+int start_simulate_task(void);
+
+extern int get_vm_status(void);
+extern void set_vm_status(int flag);
+
+/* for vm device op. */
+extern int init_vm_device(struct vm_device_s *vdevp,
+               struct platform_device *pdev);
+extern int uninit_vm_device(struct platform_device *plat_dev);
+
+/* for vm device class op. */
+extern struct class *init_vm_cls(void);
+
+/* for thread of vm. */
+extern int start_vpp_task(void);
+extern void stop_vpp_task(void);
+
+/* for vm private member. */
+extern void set_vm_buf_info(resource_size_t start, unsigned int size);
+extern void get_vm_buf_info(resource_size_t *start, unsigned int *size,
+                           struct io_mapping **mapping);
+
+/*  vm buffer op. */
+extern int vm_buffer_init(struct vm_device_s *vdevp);
+extern void vm_local_init(void);
+
+extern void vm_deinit_resource(struct vm_init_s *info);
+
+static DEFINE_MUTEX(vm_mutex);
+
+/* #if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6TV */
+#if 1
+#define CANVAS_WIDTH_ALIGN 32
+#else
+#define CANVAS_WIDTH_ALIGN 8
+#endif
+
+#define MAGIC_SG_MEM    0x17890714
+#define MAGIC_DC_MEM    0x0733ac61
+#define MAGIC_VMAL_MEM  0x18221223
+#define MAGIC_RE_MEM    0x123039dc
+
+#endif /* _VM_INCLUDE__ */
diff --git a/drivers/amlogic/media/camera/common/vm_log.h b/drivers/amlogic/media/camera/common/vm_log.h
new file mode 100644 (file)
index 0000000..4733cad
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * drivers/amlogic/media/camera/common/vm_log.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 VM_LOG_H
+#define  VM_LOG_H
+
+#define DEBUG
+#ifdef DEBUG
+#define  AMLOG   1
+#define LOG_LEVEL_VAR amlog_level_ppmgr
+#define LOG_MASK_VAR amlog_mask_ppmgr
+#endif
+
+#define        LOG_LEVEL_HIGH          0x00f
+#define        LOG_LEVEL_1                             0x001
+#define        LOG_LEVEL_LOW                   0x000
+
+#define LOG_LEVEL_DESC \
+"[0x00]LOW[0X01]LEVEL1[0xf]HIGH"
+
+#define        LOG_MASK_INIT                   0x001
+#define        LOG_MASK_IOCTL                  0x002
+#define        LOG_MASK_HARDWARE               0x004
+#define        LOG_MASK_CONFIG         0x008
+#define        LOG_MASK_WORK                   0x010
+#define        LOG_MASK_DESC \
+"[0x01]:INIT,[0x02]:IOCTL,[0x04]:HARDWARE,[0x08]LOG_MASK_CONFIG[0x10]LOG_MASK_WORK"
+
+#endif
+
diff --git a/drivers/amlogic/media/camera/common/vmcls.h b/drivers/amlogic/media/camera/common/vmcls.h
new file mode 100644 (file)
index 0000000..3e81c37
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * drivers/amlogic/media/camera/common/vmcls.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#define VM_CLASS_NAME                          "vm"
+
+extern void interleave_uv(unsigned char *pU, unsigned char *pV,
+                         unsigned char *pUV, unsigned int size_u_or_v);
+
+static ssize_t show_vm_info(struct class *cla, struct class_attribute *attr,
+                           char *buf)
+{
+#if 0
+       resource_size_t bstart;
+       unsigned int bsize;
+
+       get_vm_buf_info(&bstart, &bsize, NULL);
+       return snprintf(buf, 80, "buffer:\n start:%x.\tsize:%d\n",
+               (unsigned int)bstart, bsize / (1024 * 1024));
+#endif
+       return 0;
+}
+
+static char attr_dat0[3] = "-1";
+static ssize_t read_attr0(struct class *cla, struct class_attribute *attr,
+                         char *buf)
+{
+       return snprintf(buf, 3, "%s", attr_dat0);
+}
+
+static ssize_t write_attr0(struct class *cla,
+                          struct class_attribute *attr,
+                          const char *buf, size_t count)
+{
+       /* struct display_device *dsp = dev_get_drvdata(dev); */
+       ssize_t ret = -EINVAL;
+
+       if (count <= 2) {
+               int i = 0;
+
+               if (buf[0] == '-') {
+                       attr_dat0[0] = '-';
+                       i = 1;
+                       ret++;
+               }
+               if ((buf[i] >= '0') && (buf[i] <= '9')) {
+                       attr_dat0[i] = buf[i];
+                       attr_dat0[i + 1] = '\0';
+                       ret++;
+               } else {
+                       attr_dat0[0] = '-';
+                       attr_dat0[1] = '1'; /* default -1; */
+                       ret = -EINVAL;
+               }
+       }
+
+       return ret;
+}
+
+static char attr_dat1[3] = "-1";
+static ssize_t read_attr1(struct class *cla, struct class_attribute *attr,
+                         char *buf)
+{
+       return snprintf(buf, 3, "%s", attr_dat1);
+}
+
+static ssize_t write_attr1(struct class *cla,
+                          struct class_attribute *attr,
+                          const char *buf, size_t count)
+{
+       /* struct display_device *dsp = dev_get_drvdata(dev); */
+       ssize_t ret = -EINVAL;
+
+       if (count <= 2) {
+               int i = 0;
+
+               if (buf[0] == '-') {
+                       attr_dat1[0] = '-';
+                       i = 1;
+                       ret++;
+               }
+               if ((buf[i] >= '0') && (buf[i] <= '9')) {
+                       attr_dat1[i] = buf[i];
+                       attr_dat1[i + 1] = '\0';
+                       ret++;
+               } else {
+                       attr_dat1[0] = '-';
+                       attr_dat1[1] = '1'; /* default -1; */
+                       ret = -EINVAL;
+               }
+       }
+
+       return ret;
+}
+int disable_gt2005;
+
+static ssize_t read_attr2(struct class *cla, struct class_attribute *attr,
+                         char *buf)
+{
+       return disable_gt2005;
+}
+
+static ssize_t write_attr2(struct class *cla,
+                          struct class_attribute *attr,
+                          const char *buf, size_t count)
+{
+       /* struct display_device *dsp = dev_get_drvdata(dev); */
+       ssize_t ret = -EINVAL;
+
+       if (count <= 2)
+               disable_gt2005 = buf[0];
+
+       return ret;
+}
+
+int camera_mirror_flag;  /* 0: disable, 1: l&r mirror,2 t-b mirror */
+
+static ssize_t mirror_read(struct class *cla, struct class_attribute *attr,
+                          char *buf)
+{
+       if (camera_mirror_flag == 1)
+               return snprintf(buf, 80,
+               "currnet mirror mode is l-r mirror mode. value is: %d.\n",
+               camera_mirror_flag);
+       else if (camera_mirror_flag == 2)
+               return snprintf(buf, 80,
+               "currnet mirror mode is t-b mirror mode. value is: %d.\n",
+               camera_mirror_flag);
+       else
+               return snprintf(buf, 80,
+               "currnet mirror mode is normal mode. value is: %d.\n",
+               camera_mirror_flag);
+}
+
+static ssize_t mirror_write(struct class *cla,
+                           struct class_attribute *attr,
+                           const char *buf, size_t count)
+{
+       ssize_t size;
+       char *endp = "1";
+
+       camera_mirror_flag = kstrtoul(buf, 0, (unsigned long *)endp);
+       size = endp - buf;
+       return count;
+}
+
+static struct class_attribute vm_class_attrs[] = {
+                               __ATTR(info, 0644,
+                               show_vm_info, NULL),
+                               __ATTR(attr0, 0644,
+                               read_attr0, write_attr0),
+                               __ATTR(attr1, 0644,
+                               read_attr1, write_attr1),
+                               __ATTR(attr2, 0644,
+                               read_attr2, write_attr2),
+                               __ATTR(mirror, 0644,
+                                       mirror_read, mirror_write),
+                               __ATTR_NULL
+};
+
+static struct class vm_class = {
+               .name = VM_CLASS_NAME,
+               .class_attrs = vm_class_attrs,
+       };
+
+struct class *init_vm_cls()
+       {
+               int ret = 0;
+
+               ret = class_register(&vm_class);
+               if (ret < 0) {
+                       pr_err("error create vm class\n");
+                       return NULL;
+               }
+               return &vm_class;
+       }
diff --git a/drivers/amlogic/media/camera/gc2145.c b/drivers/amlogic/media/camera/gc2145.c
new file mode 100644 (file)
index 0000000..3150faf
--- /dev/null
@@ -0,0 +1,3453 @@
+/*
+ * drivers/amlogic/media/camera/gc2145.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/sizes.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/random.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+#include <linux/amlogic/media/v4l_util/videobuf-res.h>
+#include <media/videobuf-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+#endif
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/amlogic/media/camera/aml_cam_info.h>
+#include <linux/amlogic/media/camera/vmapi.h>
+#include "common/plat_ctrl.h"
+#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/media/old_cpu_version.h>
+#include "common/vm.h"
+
+#define GC2145_CAMERA_MODULE_NAME "gc2145"
+
+/* Wake up at about 30 fps */
+#define WAKE_NUMERATOR 30
+#define WAKE_DENOMINATOR 1001
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+
+#define MAGIC_RE_MEM 0x123039dc
+#define CAMERA_USER_CANVAS_INDEX       0x4e
+
+#define GC2145_CAMERA_MAJOR_VERSION 0
+#define GC2145_CAMERA_MINOR_VERSION 7
+#define GC2145_CAMERA_RELEASE 0
+#define GC2145_CAMERA_VERSION  \
+               KERNEL_VERSION(GC2145_CAMERA_MAJOR_VERSION,     \
+               GC2145_CAMERA_MINOR_VERSION,    \
+               GC2145_CAMERA_RELEASE)
+
+#define GC2145_DRIVER_VERSION "GC2145-COMMON-01-140722"
+
+/*unsigned short DGain_shutter,AGain_shutter,*/
+/*DGain_shutterH,DGain_shutterL,AGain_shutterH,*/
+/*AGain_shutterL,shutterH,shutterL,shutter;*/
+/*unsigned short UXGA_Cap = 0;*/
+
+static struct i2c_client *g_i2c_client;
+static u32 cur_reg;
+static u8 cur_val;
+static u8 is_first_time_open;
+
+enum DCAMERA_FLICKER {
+
+       DCAMERA_FLICKER_50HZ = 0,
+
+       DCAMERA_FLICKER_60HZ,
+
+       FLICKER_MAX
+
+};
+
+/*static unsigned short Antiflicker = DCAMERA_FLICKER_50HZ;*/
+
+#define GC2145_NORMAL_Y0ffset 0x08
+#define GC2145_LOWLIGHT_Y0ffset  0x20
+
+MODULE_DESCRIPTION("gc2145 On Board");
+MODULE_AUTHOR("amlogic-sh");
+MODULE_LICENSE("GPL v2");
+
+static unsigned int video_nr = -1;  /* videoX start number, -1 is autodetect. */
+
+static unsigned int debug;
+/* module_param(debug, uint, 0644); */
+/* MODULE_PARM_DESC(debug, "activates debug info"); */
+
+static unsigned int vid_limit = 16;
+/* module_param(vid_limit, uint, 0644); */
+/* MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); */
+
+//static int vidio_set_fmt_ticks;
+
+static int GC2145_h_active = 640; /* 800; */
+static int GC2145_v_active = 480; /* 600; */
+
+static int gc2145_have_open;
+
+static struct v4l2_fract gc2145_frmintervals_active = {
+       .numerator = 1,
+       .denominator = 15,
+};
+
+static int gc2145_night_or_normal;  /* add by sp_yjp,20120905 */
+static struct vdin_v4l2_ops_s *vops;
+/* supported controls */
+static struct v4l2_queryctrl gc2145_qctrl[] = {
+       {
+               .id            = V4L2_CID_DO_WHITE_BALANCE,
+               .type          = V4L2_CTRL_TYPE_MENU,
+               .name          = "white balance",
+               .minimum       = CAM_WB_AUTO,
+               .maximum       = CAM_WB_FLUORESCENT,
+               .step          = 0x1,
+               .default_value = CAM_WB_AUTO,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_EXPOSURE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "exposure",
+               .minimum       = 0,
+               .maximum       = 8,
+               .step          = 0x1,
+               .default_value = 4,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_COLORFX,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "effect",
+               .minimum       = 0,
+               .maximum       = 6,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_POWER_LINE_FREQUENCY,
+               .type          = V4L2_CTRL_TYPE_MENU,
+               .name          = "banding",
+               .minimum       = CAM_BANDING_50HZ,
+               .maximum       = CAM_BANDING_60HZ,
+               .step          = 0x1,
+               .default_value = CAM_BANDING_50HZ,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_BLUE_BALANCE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "scene mode",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_HFLIP,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "flip on horizontal",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_VFLIP,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "flip on vertical",
+               .minimum       = 0,
+               .maximum       = 1,
+               .step          = 0x1,
+               .default_value = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id            = V4L2_CID_ZOOM_ABSOLUTE,
+               .type          = V4L2_CTRL_TYPE_INTEGER,
+               .name          = "Zoom, Absolute",
+               .minimum       = 100,
+               .maximum       = 300,
+               .step          = 20,
+               .default_value = 100,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }, {
+               .id     = V4L2_CID_ROTATE,
+               .type       = V4L2_CTRL_TYPE_INTEGER,
+               .name       = "Rotate",
+               .minimum    = 0,
+               .maximum    = 270,
+               .step       = 90,
+               .default_value  = 0,
+               .flags         = V4L2_CTRL_FLAG_SLIDER,
+       }
+};
+struct v4l2_querymenu gc2145_qmenu_wbmode[] = {
+       {
+               .id         = V4L2_CID_DO_WHITE_BALANCE,
+               .index      = CAM_WB_AUTO,
+               .name       = "auto",
+               .reserved   = 0,
+       }, {
+               .id         = V4L2_CID_DO_WHITE_BALANCE,
+               .index      = CAM_WB_CLOUD,
+               .name       = "cloudy-daylight",
+               .reserved   = 0,
+       }, {
+               .id         = V4L2_CID_DO_WHITE_BALANCE,
+               .index      = CAM_WB_INCANDESCENCE,
+               .name       = "incandescent",
+               .reserved   = 0,
+       }, {
+               .id         = V4L2_CID_DO_WHITE_BALANCE,
+               .index      = CAM_WB_DAYLIGHT,
+               .name       = "daylight",
+               .reserved   = 0,
+       }, {
+               .id         = V4L2_CID_DO_WHITE_BALANCE,
+               .index      = CAM_WB_FLUORESCENT,
+               .name       = "fluorescent",
+               .reserved   = 0,
+       }, {
+               .id         = V4L2_CID_DO_WHITE_BALANCE,
+               .index      = CAM_WB_WARM_FLUORESCENT,
+               .name       = "warm-fluorescent",
+               .reserved   = 0,
+       },
+};
+
+struct v4l2_querymenu gc2145_qmenu_anti_banding_mode[] = {
+       {
+               .id         = V4L2_CID_POWER_LINE_FREQUENCY,
+               .index      = CAM_BANDING_50HZ,
+               .name       = "50hz",
+               .reserved   = 0,
+       }, {
+               .id         = V4L2_CID_POWER_LINE_FREQUENCY,
+               .index      = CAM_BANDING_60HZ,
+               .name       = "60hz",
+               .reserved   = 0,
+       },
+};
+static struct v4l2_frmivalenum gc2145_frmivalenum[] = {
+       {
+               .index          = 0,
+               .pixel_format   = V4L2_PIX_FMT_NV21,
+               .width          = 352,
+               .height         = 288,
+               .type           = V4L2_FRMIVAL_TYPE_DISCRETE,
+               {
+                       .discrete = {
+                               .numerator = 1,
+                               .denominator = 30,/* 15 */
+                       }
+               }
+       }, {
+               .index      = 0,
+               .pixel_format   = V4L2_PIX_FMT_NV21,
+               .width      = 640,
+               .height     = 480,
+               .type       = V4L2_FRMIVAL_TYPE_DISCRETE,
+               {
+                       .discrete   = {
+                               .numerator  = 1,
+                               .denominator    = 30,/* 15 */
+                       }
+               }
+       }, {
+               .index      = 1,
+               .pixel_format   = V4L2_PIX_FMT_NV21,
+               .width      = 1600,
+               .height     = 1200,
+               .type       = V4L2_FRMIVAL_TYPE_DISCRETE,
+               {
+                       .discrete   = {
+                               .numerator  = 1,
+                               .denominator    = 5,
+                       }
+               }
+       },
+};
+
+
+struct gc2145_qmenu_set_s {
+       __u32   id;
+       int     num;
+       struct v4l2_querymenu *gc2145_qmenu;
+};
+
+struct gc2145_qmenu_set_s gc2145_qmenu_set[] = {
+       {
+               .id             = V4L2_CID_DO_WHITE_BALANCE,
+               .num            = ARRAY_SIZE(gc2145_qmenu_wbmode),
+               .gc2145_qmenu   = gc2145_qmenu_wbmode,
+       }, {
+               .id             = V4L2_CID_POWER_LINE_FREQUENCY,
+               .num            = ARRAY_SIZE(gc2145_qmenu_anti_banding_mode),
+               .gc2145_qmenu   = gc2145_qmenu_anti_banding_mode,
+       },
+};
+
+static int vidioc_querymenu(struct file *file, void *priv,
+                           struct v4l2_querymenu *a)
+{
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(gc2145_qmenu_set); i++) {
+               if (a->id && a->id == gc2145_qmenu_set[i].id) {
+                       for (j = 0; j < gc2145_qmenu_set[i].num; j++) {
+                               if (a->index ==
+                               gc2145_qmenu_set[i].gc2145_qmenu[j].index) {
+                                       memcpy(a,
+                                       &(gc2145_qmenu_set[i].gc2145_qmenu[j]),
+                                       sizeof(*a));
+                                       return 0;
+                               }
+                       }
+               }
+       }
+       return -EINVAL;
+}
+
+#define dprintk(dev, level, fmt, arg...)       \
+               v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
+
+/*
+ * ------------------------------------------------------------------
+ *    Basic structures
+ * ------------------------------------------------------------------
+ */
+
+struct gc2145_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+};
+
+static struct gc2145_fmt formats[] = {
+       {
+               .name     = "RGB565 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+               .depth    = 16,
+       }, {
+               .name     = "RGB888 (24)",
+               .fourcc   = V4L2_PIX_FMT_RGB24, /* 24  RGB-8-8-8 */
+               .depth    = 24,
+       }, {
+               .name     = "BGR888 (24)",
+               .fourcc   = V4L2_PIX_FMT_BGR24, /* 24  BGR-8-8-8 */
+               .depth    = 24,
+       }, {
+               .name     = "12  Y/CbCr 4:2:0",
+               .fourcc   = V4L2_PIX_FMT_NV12,
+               .depth    = 12,
+       }, {
+               .name     = "12  Y/CbCr 4:2:0",
+               .fourcc   = V4L2_PIX_FMT_NV21,
+               .depth    = 12,
+       }, {
+               .name     = "YUV420P",
+               .fourcc   = V4L2_PIX_FMT_YUV420,
+               .depth    = 12,
+       }, {
+               .name     = "YVU420P",
+               .fourcc   = V4L2_PIX_FMT_YVU420,
+               .depth    = 12,
+       }
+};
+
+static struct gc2145_fmt *get_format(struct v4l2_format *f)
+{
+       struct gc2145_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < ARRAY_SIZE(formats); k++) {
+               fmt = &formats[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (k == ARRAY_SIZE(formats))
+               return NULL;
+
+       return &formats[k];
+}
+
+struct sg_to_addr {
+       int pos;
+       struct scatterlist *sg;
+};
+
+/* buffer for one video frame */
+struct gc2145_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct videobuf_buffer vb;
+
+       struct gc2145_fmt        *fmt;
+
+       unsigned int canvas_id;
+};
+
+struct gc2145_dmaqueue {
+       struct list_head       active;
+
+       /* thread for generating video stream*/
+       struct task_struct         *kthread;
+       wait_queue_head_t          wq;
+       /* Counters to control fps rate */
+       int                        frame;
+       int                        ini_jiffies;
+};
+
+static LIST_HEAD(gc2145_devicelist);
+
+struct gc2145_device {
+       struct list_head            gc2145_devicelist;
+       struct v4l2_subdev          sd;
+       struct v4l2_device          v4l2_dev;
+
+       spinlock_t                 slock;
+       struct mutex                mutex;
+
+       int                        users;
+
+       /* various device info */
+       struct video_device        *vdev;
+
+       struct gc2145_dmaqueue       vidq;
+
+       /* Several counters */
+       unsigned long              jiffies;
+
+       /* Input Number */
+       int            input;
+
+       /* platform device data from board initting. */
+       struct aml_cam_info_s  cam_info;
+
+#ifdef CONFIG_HAS_WAKELOCK
+       /* wake lock */
+       struct wake_lock    wake_lock;
+#endif
+
+       /* Control 'registers' */
+       int                qctl_regs[ARRAY_SIZE(gc2145_qctrl)];
+       struct vm_init_s vminfo;
+};
+
+static inline struct gc2145_device *to_dev(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct gc2145_device, sd);
+}
+
+struct gc2145_fh {
+       struct gc2145_device            *dev;
+
+       /* video capture */
+       struct gc2145_fmt            *fmt;
+       unsigned int               width, height;
+       struct videobuf_queue      vb_vidq;
+
+       struct videobuf_res_privdata res;
+       enum v4l2_buf_type         type;
+       int            input;   /* Input Number on bars */
+       int  stream_on;
+       unsigned int        f_flags;
+};
+
+/*
+ *static inline struct gc2145_fh *to_fh(struct gc2145_device *dev)
+ *{
+ *    return container_of(dev, struct gc2145_fh, dev);
+ *}
+ */
+
+static struct v4l2_frmsize_discrete
+       gc2145_prev_resolution[] = {
+       /* should include 352x288 and 640x480,*/
+       /*those two size are used for recording*/
+       {352, 288},
+       {640, 480},
+};
+
+static struct v4l2_frmsize_discrete gc2145_pic_resolution[] = {
+       {1600, 1200},
+       {800, 600}
+};
+
+#ifndef GC2145_MIRROR
+#define GC2145_MIRROR   0
+#endif
+#ifndef GC2145_FLIP
+#define GC2145_FLIP   0
+#endif
+
+/*
+ *------------------------------------------------------------------
+ *    reg spec of GC2145
+ *   ------------------------------------------------------------------
+ */
+
+struct aml_camera_i2c_fig_s GC2145_script[] = {
+       /*SENSORDB("GC2145_Sensor_Init"}*/
+       {0xfe, 0xf0},
+       {0xfe, 0xf0},
+       {0xfe, 0xf0},
+       {0xfc, 0x06},
+       {0xf6, 0x00},
+       {0xf7, 0x1d},
+       {0xf8, 0x84},
+       {0xfa, 0x00},
+       {0xf9, 0xfe},
+       {0xf2, 0x00},
+       /*ISP reg*/
+       {0xfe, 0x00},
+       {0x03, 0x04},
+       {0x04, 0xe2},
+       {0x09, 0x00},
+       {0x0a, 0x00},
+       {0x0b, 0x00},
+       {0x0c, 0x00},
+       {0x0d, 0x04},
+       {0x0e, 0xc0},
+       {0x0f, 0x06},
+       {0x10, 0x52},
+       {0x12, 0x2e},
+       {0x17, 0x14}, /*mirror*/
+       {0x18, 0x22},
+       {0x19, 0x0e},
+       {0x1a, 0x01},
+       {0x1b, 0x4b},
+       {0x1c, 0x07},
+       {0x1d, 0x10},
+       {0x1e, 0x88},
+       {0x1f, 0x78},
+       {0x20, 0x03},
+       {0x21, 0x40},
+       {0x22, 0xa0},
+       {0x24, 0x16},
+       {0x25, 0x01},
+       {0x26, 0x10},
+       {0x2d, 0x60},
+       {0x30, 0x01},
+       {0x31, 0x90},
+       {0x33, 0x06},
+       {0x34, 0x01},
+       /*ISP reg*/
+       {0xfe, 0x00},
+       {0x80, 0x7f},
+       {0x81, 0x26},
+       {0x82, 0xfa},
+       {0x83, 0x00},
+       {0x84, 0x02},
+       {0x86, 0x01},/*0x03*/
+       {0x88, 0x03},
+       {0x89, 0x03},
+       {0x85, 0x08},
+       {0x8a, 0x00},
+       {0x8b, 0x00},
+       {0xb0, 0x55},
+       {0xc3, 0x00},
+       {0xc4, 0x80},
+       {0xc5, 0x90},
+       {0xc6, 0x3b},
+       {0xc7, 0x46},
+       {0xec, 0x06},
+       {0xed, 0x04},
+       {0xee, 0x60},
+       {0xef, 0x90},
+       {0xb6, 0x01},
+       {0x90, 0x01},
+       {0x91, 0x00},
+       {0x92, 0x00},
+       {0x93, 0x00},
+       {0x94, 0x00},
+       {0x95, 0x04},
+       {0x96, 0xb0},
+       {0x97, 0x06},
+       {0x98, 0x40},
+       /*BLK*/
+       {0xfe, 0x00},
+       {0x40, 0x42},
+       {0x41, 0x00},
+       {0x43, 0x5b},
+       {0x5e, 0x00},
+       {0x5f, 0x00},
+       {0x60, 0x00},
+       {0x61, 0x00},
+       {0x62, 0x00},
+       {0x63, 0x00},
+       {0x64, 0x00},
+       {0x65, 0x00},
+       {0x66, 0x20},
+       {0x67, 0x20},
+       {0x68, 0x20},
+       {0x69, 0x20},
+       {0x76, 0x00},
+       {0x6a, 0x08},
+       {0x6b, 0x08},
+       {0x6c, 0x08},
+       {0x6d, 0x08},
+       {0x6e, 0x08},
+       {0x6f, 0x08},
+       {0x70, 0x08},
+       {0x71, 0x08},
+       {0x76, 0x00},
+       {0x72, 0xf0},
+       {0x7e, 0x3c},
+       {0x7f, 0x00},
+       {0xfe, 0x02},
+       {0x48, 0x15},
+       {0x49, 0x00},
+       {0x4b, 0x0b},
+       {0xfe, 0x00},
+       /*AEC*/
+       {0xfe, 0x01},
+       {0x01, 0x04},
+       {0x02, 0xc0},
+       {0x03, 0x04},
+       {0x04, 0x90},
+       {0x05, 0x30},
+       {0x06, 0x90},
+       {0x07, 0x30},
+       {0x08, 0x80},
+       {0x09, 0x00},
+       {0x0a, 0x82},
+       {0x0b, 0x11},
+       {0x0c, 0x10},
+       {0x11, 0x10},
+       {0x13, 0x7b},
+       {0x17, 0x00},
+       {0x1c, 0x11},
+       {0x1e, 0x61},
+       {0x1f, 0x35},
+       {0x20, 0x40},
+       {0x22, 0x40},
+       {0x23, 0x20},
+       {0xfe, 0x02},
+       {0x0f, 0x04},
+       {0xfe, 0x01},
+       {0x12, 0x35},
+       {0x15, 0xb0},
+       {0x10, 0x31},
+       {0x3e, 0x28},
+       {0x3f, 0xb0},
+       {0x40, 0x90},
+       {0x41, 0x0f},
+       /*INTPEE*/
+       {0xfe, 0x02},
+       {0x90, 0x6c},
+       {0x91, 0x03},
+       {0x92, 0xcb},
+       {0x94, 0x33},
+       {0x95, 0x84},
+       {0x97, 0x65},
+       {0xa2, 0x11},
+       {0xfe, 0x00},
+       /*DNDD*/
+       {0xfe, 0x02},
+       {0x80, 0xc1},
+       {0x81, 0x08},
+       {0x82, 0x05},
+       {0x83, 0x08},
+       {0x84, 0x0a},
+       {0x86, 0xf0},
+       {0x87, 0x50},
+       {0x88, 0x15},
+       {0x89, 0xb0},
+       {0x8a, 0x30},
+       {0x8b, 0x10},
+       /*ASDE*/
+       {0xfe, 0x01},
+       {0x21, 0x04},
+       {0xfe, 0x02},
+       {0xa3, 0x50},
+       {0xa4, 0x20},
+       {0xa5, 0x40},
+       {0xa6, 0x80},
+       {0xab, 0x40},
+       {0xae, 0x0c},
+       {0xb3, 0x46},
+       {0xb4, 0x64},
+       {0xb6, 0x38},
+       {0xb7, 0x01},
+       {0xb9, 0x2b},
+       {0x3c, 0x04},
+       {0x3d, 0x15},
+       {0x4b, 0x06},
+       {0x4c, 0x20},
+       {0xfe, 0x00},
+
+       /*gamma1*/
+#if 1
+       {0xfe, 0x02},
+       {0x10, 0x09},
+       {0x11, 0x0d},
+       {0x12, 0x13},
+       {0x13, 0x19},
+       {0x14, 0x27},
+       {0x15, 0x37},
+       {0x16, 0x45},
+       {0x17, 0x53},
+       {0x18, 0x69},
+       {0x19, 0x7d},
+       {0x1a, 0x8f},
+       {0x1b, 0x9d},
+       {0x1c, 0xa9},
+       {0x1d, 0xbd},
+       {0x1e, 0xcd},
+       {0x1f, 0xd9},
+       {0x20, 0xe3},
+       {0x21, 0xea},
+       {0x22, 0xef},
+       {0x23, 0xf5},
+       {0x24, 0xf9},
+       {0x25, 0xff},
+#else
+       {0xfe, 0x02},
+       {0x10, 0x0a},
+       {0x11, 0x12},
+       {0x12, 0x19},
+       {0x13, 0x1f},
+       {0x14, 0x2c},
+       {0x15, 0x38},
+       {0x16, 0x42},
+       {0x17, 0x4e},
+       {0x18, 0x63},
+       {0x19, 0x76},
+       {0x1a, 0x87},
+       {0x1b, 0x96},
+       {0x1c, 0xa2},
+       {0x1d, 0xb8},
+       {0x1e, 0xcb},
+       {0x1f, 0xd8},
+       {0x20, 0xe2},
+       {0x21, 0xe9},
+       {0x22, 0xf0},
+       {0x23, 0xf8},
+       {0x24, 0xfd},
+       {0x25, 0xff},
+       {0xfe, 0x00},
+#endif
+       {0xfe, 0x00},
+       {0xc6, 0x20},
+       {0xc7, 0x2b},
+       /*gamma2*/
+#if 1
+       {0xfe, 0x02},
+       {0x26, 0x0f},
+       {0x27, 0x14},
+       {0x28, 0x19},
+       {0x29, 0x1e},
+       {0x2a, 0x27},
+       {0x2b, 0x33},
+       {0x2c, 0x3b},
+       {0x2d, 0x45},
+       {0x2e, 0x59},
+       {0x2f, 0x69},
+       {0x30, 0x7c},
+       {0x31, 0x89},
+       {0x32, 0x98},
+       {0x33, 0xae},
+       {0x34, 0xc0},
+       {0x35, 0xcf},
+       {0x36, 0xda},
+       {0x37, 0xe2},
+       {0x38, 0xe9},
+       {0x39, 0xf3},
+       {0x3a, 0xf9},
+       {0x3b, 0xff},
+#else
+       /*Gamma outdoor*/
+       {0xfe, 0x02},
+       {0x26, 0x17},
+       {0x27, 0x18},
+       {0x28, 0x1c},
+       {0x29, 0x20},
+       {0x2a, 0x28},
+       {0x2b, 0x34},
+       {0x2c, 0x40},
+       {0x2d, 0x49},
+       {0x2e, 0x5b},
+       {0x2f, 0x6d},
+       {0x30, 0x7d},
+       {0x31, 0x89},
+       {0x32, 0x97},
+       {0x33, 0xac},
+       {0x34, 0xc0},
+       {0x35, 0xcf},
+       {0x36, 0xda},
+       {0x37, 0xe5},
+       {0x38, 0xec},
+       {0x39, 0xf8},
+       {0x3a, 0xfd},
+       {0x3b, 0xff},
+#endif
+       /*YCP*/
+       {0xfe, 0x02},
+       {0xd1, 0x32},
+       {0xd2, 0x32},
+       {0xd3, 0x40},
+       {0xd6, 0xf0},
+       {0xd7, 0x10},
+       {0xd8, 0xda},
+       {0xdd, 0x14},
+       {0xde, 0x86},
+       {0xed, 0x80},
+       {0xee, 0x00},
+       {0xef, 0x3f},
+       {0xd8, 0xd8},
+       /*abs*/
+       {0xfe, 0x01},
+       {0x9f, 0x40},
+       /*LSC*/
+       {0xfe, 0x01},
+       {0xc2, 0x14},
+       {0xc3, 0x0d},
+       {0xc4, 0x0c},
+       {0xc8, 0x15},
+       {0xc9, 0x0d},
+       {0xca, 0x0a},
+       {0xbc, 0x24},
+       {0xbd, 0x10},
+       {0xbe, 0x0b},
+       {0xb6, 0x25},
+       {0xb7, 0x16},
+       {0xb8, 0x15},
+       {0xc5, 0x00},
+       {0xc6, 0x00},
+       {0xc7, 0x00},
+       {0xcb, 0x00},
+       {0xcc, 0x00},
+       {0xcd, 0x00},
+       {0xbf, 0x07},
+       {0xc0, 0x00},
+       {0xc1, 0x00},
+       {0xb9, 0x00},
+       {0xba, 0x00},
+       {0xbb, 0x00},
+       {0xaa, 0x01},
+       {0xab, 0x01},
+       {0xac, 0x00},
+       {0xad, 0x05},
+       {0xae, 0x06},
+       {0xaf, 0x0e},
+       {0xb0, 0x0b},
+       {0xb1, 0x07},
+       {0xb2, 0x06},
+       {0xb3, 0x17},
+       {0xb4, 0x0e},
+       {0xb5, 0x0e},
+       {0xd0, 0x09},
+       {0xd1, 0x00},
+       {0xd2, 0x00},
+       {0xd6, 0x08},
+       {0xd7, 0x00},
+       {0xd8, 0x00},
+       {0xd9, 0x00},
+       {0xda, 0x00},
+       {0xdb, 0x00},
+       {0xd3, 0x0a},
+       {0xd4, 0x00},
+       {0xd5, 0x00},
+       {0xa4, 0x00},
+       {0xa5, 0x00},
+       {0xa6, 0x77},
+       {0xa7, 0x77},
+       {0xa8, 0x77},
+       {0xa9, 0x77},
+       {0xa1, 0x80},
+       {0xa2, 0x80},
+       {0xfe, 0x01},
+       {0xdf, 0x0d},
+       {0xdc, 0x25},
+       {0xdd, 0x30},
+       {0xe0, 0x77},
+       {0xe1, 0x80},
+       {0xe2, 0x77},
+       {0xe3, 0x90},
+       {0xe6, 0x90},
+       {0xe7, 0xa0},
+       {0xe8, 0x90},
+       {0xe9, 0xa0},
+       {0xfe, 0x00},
+       /*AWB*/
+       {0xfe, 0x01},
+       {0x4f, 0x00},
+       {0x4f, 0x00},
+       {0x4b, 0x01},
+       {0x4f, 0x00},
+       {0x4c, 0x01}, /*D75*/
+       {0x4d, 0x71},
+       {0x4e, 0x01},
+       {0x4c, 0x01},
+       {0x4d, 0x91},
+       {0x4e, 0x01},
+       {0x4c, 0x01},
+       {0x4d, 0x70},
+       {0x4e, 0x01},
+       {0x4c, 0x01}, /*D65*/
+       {0x4d, 0x90},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0xb0},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0x8f},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0x6f},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0xaf},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0xd0},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0xf0},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0xcf},
+       {0x4e, 0x02},
+       {0x4c, 0x01},
+       {0x4d, 0xef},
+       {0x4e, 0x02},
+       {0x4c, 0x01},/*D50*/
+       {0x4d, 0x6e},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x8e},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xae},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xce},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x4d},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x6d},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x8d},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xad},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xcd},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x4c},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x6c},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x8c},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xac},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xcc},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xcb},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x4b},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x6b},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0x8b},
+       {0x4e, 0x03},
+       {0x4c, 0x01},
+       {0x4d, 0xab},
+       {0x4e, 0x03},
+       {0x4c, 0x01},/*CWF*/
+       {0x4d, 0x8a},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0xaa},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0xca},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0xca},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0xc9},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0x8a},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0x89},
+       {0x4e, 0x04},
+       {0x4c, 0x01},
+       {0x4d, 0xa9},
+       {0x4e, 0x04},
+       {0x4c, 0x02},/*tl84*/
+       {0x4d, 0x0b},
+       {0x4e, 0x05},
+       {0x4c, 0x02},
+       {0x4d, 0x0a},
+       {0x4e, 0x05},
+       {0x4c, 0x01},
+       {0x4d, 0xeb},
+       {0x4e, 0x05},
+       {0x4c, 0x01},
+       {0x4d, 0xea},
+       {0x4e, 0x05},
+       {0x4c, 0x02},
+       {0x4d, 0x09},
+       {0x4e, 0x05},
+       {0x4c, 0x02},
+       {0x4d, 0x29},
+       {0x4e, 0x05},
+       {0x4c, 0x02},
+       {0x4d, 0x2a},
+       {0x4e, 0x05},
+       {0x4c, 0x02},
+       {0x4d, 0x4a},
+       {0x4e, 0x05},
+       /*{0x4c , 0x02},*/
+       /*{0x4d , 0x6a},*/
+       /*{0x4e , 0x06},*/
+       {0x4c, 0x02},
+       {0x4d, 0x8a},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0x49},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0x69},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0x89},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0xa9},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0x48},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0x68},
+       {0x4e, 0x06},
+       {0x4c, 0x02},
+       {0x4d, 0x69},
+       {0x4e, 0x06},
+       {0x4c, 0x02},/*H*/
+       {0x4d, 0xca},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xc9},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xe9},
+       {0x4e, 0x07},
+       {0x4c, 0x03},
+       {0x4d, 0x09},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xc8},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xe8},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xa7},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xc7},
+       {0x4e, 0x07},
+       {0x4c, 0x02},
+       {0x4d, 0xe7},
+       {0x4e, 0x07},
+       {0x4c, 0x03},
+       {0x4d, 0x07},
+       {0x4e, 0x07},
+       {0x4f, 0x01},
+       {0x50, 0x80},
+       {0x51, 0xa8},
+       {0x52, 0x47},
+       {0x53, 0x38},
+       {0x54, 0xc7},
+       {0x56, 0x0e},
+       {0x58, 0x08},
+       {0x5b, 0x00},
+       {0x5c, 0x74},
+       {0x5d, 0x8b},
+       {0x61, 0xdb},
+       {0x62, 0xb8},
+       {0x63, 0x86},
+       {0x64, 0xc0},
+       {0x65, 0x04},
+       {0x67, 0xa8},
+       {0x68, 0xb0},
+       {0x69, 0x00},
+       {0x6a, 0xa8},
+       {0x6b, 0xb0},
+       {0x6c, 0xaf},
+       {0x6d, 0x8b},
+       {0x6e, 0x50},
+       {0x6f, 0x18},
+       {0x73, 0xf0},
+       {0x70, 0x0d},
+       {0x71, 0x60},
+       {0x72, 0x80},
+       {0x74, 0x01},
+       {0x75, 0x01},
+       {0x7f, 0x0c},
+       {0x76, 0x70},
+       {0x77, 0x58},
+       {0x78, 0xa0},
+       {0x79, 0x5e},
+       {0x7a, 0x54},
+       {0x7b, 0x58},
+       {0xfe, 0x00},
+       /*CC*/
+       {0xfe, 0x02},
+       {0xc0, 0x01},
+       {0xc1, 0x44},
+       {0xc2, 0xfd},
+       {0xc3, 0x04},
+       {0xc4, 0xF0},
+       {0xc5, 0x48},
+       {0xc6, 0xfd},
+       {0xc7, 0x46},
+       {0xc8, 0xfd},
+       {0xc9, 0x02},
+       {0xca, 0xe0},
+       {0xcb, 0x45},
+       {0xcc, 0xec},
+       {0xcd, 0x48},
+       {0xce, 0xf0},
+       {0xcf, 0xf0},
+       {0xe3, 0x0c},
+       {0xe4, 0x4b},
+       {0xe5, 0xe0},
+       /*ABS*/
+       {0xfe, 0x01},
+       {0x9f, 0x40},
+       {0xfe, 0x00},
+       /*OUTPUT*/
+       {0xfe, 0x00},
+       {0xf2, 0x0f},
+       /*dark sun*/
+       {0xfe, 0x02},
+       {0x40, 0xbf},
+       {0x46, 0xcf},
+       {0xfe, 0x00},
+       /*frame rate 50Hz*/
+       {0xfe, 0x00},
+       {0x05, 0x01},
+       {0x06, 0x56},
+       {0x07, 0x00},
+       {0x08, 0x32},
+       {0xfe, 0x01},
+       {0x25, 0x00},
+       {0x26, 0xfa},
+       {0x27, 0x04},
+       {0x28, 0xe2}, /*20fps*/
+       {0x29, 0x06},
+       {0x2a, 0xd6}, /*14fps*/
+       {0x2b, 0x07},
+       {0x2c, 0xd0}, /*12fps*/
+       {0x2d, 0x0b},
+       {0x2e, 0xb8}, /*8fps*/
+       {0xfe, 0x00},
+
+       /*SENSORDB("GC2145_Sensor_SVGA"},*/
+
+       {0xfe, 0x00},
+       {0xfd, 0x01},
+       {0xfa, 0x00},
+       /*crop window*/
+       {0xfe, 0x00},
+       {0x90, 0x01},
+       {0x91, 0x00},
+       {0x92, 0x00},
+       {0x93, 0x00},
+       {0x94, 0x00},
+       {0x95, 0x02},
+       {0x96, 0x58},
+       {0x97, 0x03},
+       {0x98, 0x20},
+       {0x99, 0x11},
+       {0x9a, 0x06},
+       /*AWB*/
+       {0xfe, 0x00},
+       {0xec, 0x02},
+       {0xed, 0x02},
+       {0xee, 0x30},
+       {0xef, 0x48},
+       {0xfe, 0x02},
+       {0x9d, 0x08},
+       {0xfe, 0x01},
+       {0x74, 0x00},
+       /*AEC*/
+       {0xfe, 0x01},
+       {0x01, 0x04},
+       {0x02, 0x60},
+       {0x03, 0x02},
+       {0x04, 0x48},
+       {0x05, 0x18},
+       {0x06, 0x50},
+       {0x07, 0x10},
+       {0x08, 0x38},
+       {0x0a, 0x80},
+       {0x21, 0x04},
+       {0xfe, 0x00},
+       {0x20, 0x03},
+       {0xfe, 0x00},
+       {0xff, 0xff},
+};
+
+struct aml_camera_i2c_fig_s gc2145_svga[] = {
+       {0xfe, 0x00},
+       {0xb6, 0x01},
+       {0xfd, 0x01},
+       {0xfa, 0x11},
+       /*crop window*/
+       {0xfe, 0x00},
+       {0x90, 0x01},
+       {0x91, 0x00},
+       {0x92, 0x00},
+       {0x93, 0x00},
+       {0x94, 0x00},
+       {0x95, 0x02},
+       {0x96, 0x5a},
+       {0x97, 0x03},
+       {0x98, 0x22},
+       {0x99, 0x11},
+       {0x9a, 0x06},
+       /*AWB*/
+       {0xfe, 0x00},
+       {0xec, 0x02},
+       {0xed, 0x02},
+       {0xee, 0x30},
+       {0xef, 0x48},
+       {0xfe, 0x02},
+       {0x9d, 0x08},
+       {0xfe, 0x01},
+       {0x74, 0x00},
+       /*AEC*/
+       {0xfe, 0x01},
+       {0x01, 0x04},
+       {0x02, 0x60},
+       {0x03, 0x02},
+       {0x04, 0x48},
+       {0x05, 0x18},
+       {0x06, 0x50},
+       {0x07, 0x10},
+       {0x08, 0x38},
+       {0x0a, 0x80},
+       {0x21, 0x04},
+       {0xfe, 0x00},
+       {0x20, 0x03},
+       {0xfe, 0x00},
+       {0xff, 0xff},
+};
+
+struct aml_camera_i2c_fig_s gc2145_uxga[] = {
+       {0xfe, 0x00},
+       {0xfd, 0x00},
+       {0xfa, 0x11},
+       /*crop window*/
+       {0xfe, 0x00},
+       {0x90, 0x01},
+       {0x91, 0x00},
+       {0x92, 0x00},
+       {0x93, 0x00},
+       {0x94, 0x00},
+       {0x95, 0x04},
+       {0x96, 0xb2},
+       {0x97, 0x06},
+       {0x98, 0x42},
+       {0x99, 0x11},
+       {0x9a, 0x06},
+       /*AWB*/
+       {0xfe, 0x00},
+       {0xec, 0x06},
+       {0xed, 0x04},
+       {0xee, 0x60},
+       {0xef, 0x90},
+       {0xfe, 0x01},
+       {0x74, 0x01},
+       /*AEC*/
+       {0xfe, 0x01},
+       {0x01, 0x04},
+       {0x02, 0xc0},
+       {0x03, 0x04},
+       {0x04, 0x90},
+       {0x05, 0x30},
+       {0x06, 0x90},
+       {0x07, 0x30},
+       {0x08, 0x80},
+       {0x0a, 0x82},
+       {0xfe, 0x01},
+       {0x21, 0x15},
+       {0xfe, 0x00},
+       {0x20, 0x15},
+       {0xfe, 0x00},
+       {0xff, 0xff},
+};
+
+struct aml_camera_i2c_fig_s gc2145_1280x960[] = {
+       /*1280X960*/
+       {0xfe, 0x00},
+       {0xfa, 0x11},
+       {0xfd, 0x00},
+       {0x1c, 0x05},
+       /*crop window*/
+       {0xfe, 0x00},
+       {0x99, 0x55},
+       {0x9a, 0x06},
+       {0x9b, 0x00},
+       {0x9c, 0x00},
+       {0x9d, 0x01},
+       {0x9e, 0x23},
+       {0x9f, 0x00},
+       {0xa0, 0x00},
+       {0xa1, 0x01},
+       {0xa2, 0x23},
+       {0x90, 0x01},
+       {0x91, 0x00},
+       {0x92, 0x00},
+       {0x93, 0x00},
+       {0x94, 0x00},
+       {0x95, 0x03},
+       {0x96, 0xc0},
+       {0x97, 0x05},
+       {0x98, 0x00},
+
+       /*AWB*/
+       {0xfe, 0x00},
+       {0xec, 0x06},
+       {0xed, 0x04},
+       {0xee, 0x60},
+       {0xef, 0x90},
+       {0xfe, 0x01},
+       {0x74, 0x01},
+       /*AEC*/
+       {0xfe, 0x01},
+       {0x01, 0x04},
+       {0x02, 0xc0},
+       {0x03, 0x04},
+       {0x04, 0x90},
+       {0x05, 0x30},
+       {0x06, 0x90},
+       {0x07, 0x30},
+       {0x08, 0x80},
+       {0x0a, 0x82},
+       {0x21, 0x15},
+       {0xfe, 0x00},
+       {0x20, 0x15},
+       {0xfe, 0x00},
+};
+
+struct aml_camera_i2c_fig_s gc2145_FLICKER_50HZ[] = {
+       {0xfe, 0x00},
+       {0x05, 0x01},
+       {0x06, 0x56},
+       {0x07, 0x00},
+       {0x08, 0x32},
+       {0xfe, 0x01},
+       {0x25, 0x00},
+       {0x26, 0xfa},
+       {0x27, 0x04},
+       {0x28, 0xe2}, /*20fps*/
+       {0x29, 0x06},
+       {0x2a, 0xd6}, /*14fps*/
+       {0x2b, 0x07},
+       {0x2c, 0xd0}, /*12fps*/
+       {0x2d, 0x0b},
+       {0x2e, 0xb8}, /*8fps*/
+       {0xfe, 0x00},
+       {0xff, 0xff},
+};
+struct aml_camera_i2c_fig_s gc2145_FLICKER_60HZ[] = {
+       {0x05, 0x01},/*hb*/
+       {0x06, 0x58},
+       {0x07, 0x00},/*vb*/
+       {0x08, 0x32},
+       {0xfe, 0x01},
+       {0x25, 0x00},/*step*/
+       {0x26, 0xd0},
+       {0x27, 0x04},/*level1*/
+       {0x28, 0xe0},
+       {0x29, 0x06},/*level2*/
+       {0x2a, 0x80},
+       {0x2b, 0x08},/*level3*/
+       {0x2c, 0x20},
+       {0x2d, 0x0b},/*level4*/
+       {0x2e, 0x60},
+       {0xfe, 0x00},
+       {0xff, 0xff},
+};
+
+/* load GC2145 parameters */
+void GC2145_init_regs(struct gc2145_device *dev)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       int i = 0;
+
+       if (!dev->vminfo.isused)
+               return;
+
+       while (1) {
+               if (GC2145_script[i].val == 0xff &&
+                       GC2145_script[i].addr == 0xff) {
+                       pr_info("GC2145_write_regs success in initial.\n");
+                       break;
+               }
+               if ((i2c_put_byte_add8_new(client, GC2145_script[i].addr,
+                                          GC2145_script[i].val)) < 0) {
+                       pr_err("fail in initial GC2145.\n");
+                       return;
+               }
+               i++;
+       }
+}
+
+/*
+ ************************************************************************
+ * FUNCTION
+ *    GC2145_set_param_wb
+ *
+ * DESCRIPTION
+ *    wb setting.
+ *
+ * PARAMETERS
+ *    none
+ *
+ * RETURNS
+ *    None
+ *
+ * GLOBALS AFFECTED
+ *
+ ************************************************************************
+ */
+
+void GC2145_set_param_wb(struct gc2145_device *dev,
+                        enum  camera_wb_flip_e para) /* white balance */
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       unsigned int temp = 0;
+
+       if (!dev->vminfo.isused)
+               return;
+
+       i2c_put_byte_add8_new(client, 0xfe, 0x00);
+       temp = i2c_get_byte_add8(client, 0x82);
+
+       switch (para) {
+
+       case CAM_WB_AUTO:/* auto */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0xb3, 0x61);
+               i2c_put_byte_add8_new(client, 0xb4, 0x40);
+               i2c_put_byte_add8_new(client, 0xb5, 0x61);
+               i2c_put_byte_add8_new(client, 0x82, temp|0x2);
+               break;
+
+       case CAM_WB_CLOUD: /* cloud */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x82, temp&(~0x02));
+               i2c_put_byte_add8_new(client, 0xb3, 0x58);
+               i2c_put_byte_add8_new(client, 0xb4, 0x40);
+               i2c_put_byte_add8_new(client, 0xb5, 0x50);
+               break;
+
+       case CAM_WB_DAYLIGHT: /*  */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x82, temp&(~0x02));
+               i2c_put_byte_add8_new(client, 0xb3, 0x70);
+               i2c_put_byte_add8_new(client, 0xb4, 0x40);
+               i2c_put_byte_add8_new(client, 0xb5, 0x50);
+               break;
+
+       case CAM_WB_INCANDESCENCE:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x82, temp&(~0x02));
+               i2c_put_byte_add8_new(client, 0xb3, 0x50);
+               i2c_put_byte_add8_new(client, 0xb4, 0x40);
+               i2c_put_byte_add8_new(client, 0xb5, 0xa8);
+               break;
+
+       case CAM_WB_TUNGSTEN:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x82, temp&(~0x02));
+               i2c_put_byte_add8_new(client, 0xb3, 0xa0);
+               i2c_put_byte_add8_new(client, 0xb4, 0x45);
+               i2c_put_byte_add8_new(client, 0xb5, 0x40);
+               break;
+
+       case CAM_WB_FLUORESCENT:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x82, temp&(~0x02));
+               i2c_put_byte_add8_new(client, 0xb3, 0x72);
+               i2c_put_byte_add8_new(client, 0xb4, 0x40);
+               i2c_put_byte_add8_new(client, 0xb5, 0x5b);
+               break;
+
+       case CAM_WB_MANUAL:
+               /* TODO */
+               break;
+       default:
+               break;
+       }
+
+
+} /* GC2145_set_param_wb */
+
+/*
+ ************************************************************************
+ * FUNCTION
+ *    GC2145_set_param_exposure
+ *
+ * DESCRIPTION
+ *    exposure setting.
+ *
+ * PARAMETERS
+ *    none
+ *
+ * RETURNS
+ *    None
+ *
+ * GLOBALS AFFECTED
+ *
+ ************************************************************************
+ */
+
+void GC2145_set_param_exposure(struct gc2145_device *dev,
+                              enum camera_exposure_e para)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+
+       if (!dev->vminfo.isused)
+               return;
+
+       switch (para) {
+
+       case EXPOSURE_N4_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x55); /*target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+
+
+       case EXPOSURE_N3_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x60); /*target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+
+       case EXPOSURE_N2_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x65); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+
+       case EXPOSURE_N1_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x70); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+       case EXPOSURE_0_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x7b); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+       case EXPOSURE_P1_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x85); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+       case EXPOSURE_P2_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x90); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+       case EXPOSURE_P3_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x95); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+       case EXPOSURE_P4_STEP:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0xa0); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+
+       default:
+               i2c_put_byte_add8_new(client, 0xfe, 0x01);
+               i2c_put_byte_add8_new(client, 0x13, 0x7b); /* target_y */
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               break;
+               /* break; */
+
+       }
+
+} /* GC2145_set_param_exposure */
+
+/*
+ ************************************************************************
+ * FUNCTION
+ *    GC2145_set_param_effect
+ *
+ * DESCRIPTION
+ *    effect setting.
+ *
+ * PARAMETERS
+ *    none
+ *
+ * RETURNS
+ *    None
+ *
+ * GLOBALS AFFECTED
+ *
+ ************************************************************************
+ */
+
+void GC2145_set_param_effect(struct gc2145_device *dev,
+                            enum camera_effect_flip_e para)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+
+       if (!dev->vminfo.isused)
+               return;
+
+       switch (para) {
+       case CAM_EFFECT_ENC_NORMAL:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x83, 0xe0);
+               break;
+
+       case CAM_EFFECT_ENC_GRAYSCALE:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x83, 0x12);
+               break;
+
+       case CAM_EFFECT_ENC_SEPIA:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x83, 0x82);
+               break;
+
+       case CAM_EFFECT_ENC_SEPIAGREEN:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x43, 0x52);
+               break;
+
+       case CAM_EFFECT_ENC_SEPIABLUE:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x43, 0x62);
+               break;
+
+       case CAM_EFFECT_ENC_COLORINV:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x83, 0x01);
+               break;
+
+       default:
+               i2c_put_byte_add8_new(client, 0xfe, 0x00);
+               i2c_put_byte_add8_new(client, 0x83, 0xe0);
+               break;
+       }
+
+} /* GC2145_set_param_effect */
+
+/*
+ ************************************************************************
+ * FUNCTION
+ *    GC2145_NightMode
+ *
+ * DESCRIPTION
+ *    This function night mode of GC2145.
+ *
+ * PARAMETERS
+ *    none
+ *
+ * RETURNS
+ *    None
+ *
+ * GLOBALS AFFECTED
+ *
+ ************************************************************************
+ */
+
+void GC2145_set_night_mode(struct gc2145_device *dev,
+                          enum  camera_night_mode_flip_e enable)
+{
+
+}
+
+void GC2145_set_param_banding(struct gc2145_device *dev,
+                             enum  camera_banding_flip_e banding)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       unsigned char buf[4];
+       int i = 0;
+
+       switch (banding) {
+       case CAM_BANDING_50HZ:
+               while (1) {
+                       buf[0] = gc2145_FLICKER_50HZ[i].addr;
+                       buf[1] = gc2145_FLICKER_50HZ[i].val;
+                       if (gc2145_FLICKER_50HZ[i].val == 0xff &&
+                            gc2145_FLICKER_50HZ[i].addr == 0xff) {
+                               pr_err("success in gc2145_FLICKER_50HZ gc2145\n");
+                               break;
+                       }
+                       if ((i2c_put_byte_add8(client, buf, 2)) < 0) {
+                               pr_err("fail in gc2145_FLICKER_50HZ gc2145\n");
+                               return;
+                       }
+                       i++;
+               }
+               break;
+       case CAM_BANDING_60HZ:
+               while (1) {
+                       buf[0] = gc2145_FLICKER_60HZ[i].addr;
+                       buf[1] = gc2145_FLICKER_60HZ[i].val;
+                       if (gc2145_FLICKER_60HZ[i].val == 0xff &&
+                            gc2145_FLICKER_60HZ[i].addr == 0xff) {
+                               pr_err("success in gc2145_FLICKER_60HZ gc2145\n");
+                               break;
+                       }
+                       if ((i2c_put_byte_add8(client, buf, 2)) < 0) {
+                               pr_err("fail in gc2145_FLICKER_60HZ gc2145\n");
+                               return;
+                       }
+                       i++;
+               }
+               break;
+       default:
+               break;
+       }
+
+}
+
+static int set_flip(struct gc2145_device *dev)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       unsigned char temp;
+       unsigned char buf[2];
+
+       if (!dev->vminfo.isused)
+               return 0;
+
+       i2c_put_byte_add8_new(client, 0xfe, 0x00);
+
+       temp = i2c_get_byte_add8(client, 0x17);
+       temp &= 0xfc;
+       temp |= dev->cam_info.m_flip << 0;
+       temp |= dev->cam_info.v_flip << 1;
+       buf[0] = 0x17;
+       buf[1] = temp;
+       if ((i2c_put_byte_add8(client, buf, 2)) < 0) {
+               pr_err("fail in setting sensor orientation\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+void GC2145_set_resolution(struct gc2145_device *dev, int height, int width)
+{
+       unsigned char buf[4];
+       unsigned int value;
+       unsigned int pid = 0, shutter;
+       unsigned int i = 0;
+       static unsigned int shutter_l;
+       static unsigned int shutter_h;
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+
+       pr_info("%s :wxh = %d x %d\n", __func__, width, height);
+
+       if (!dev->vminfo.isused)
+               return;
+
+       if ((width * height < 1600 * 1200)) {
+               while (1) {
+                       buf[0] = gc2145_svga[i].addr;
+                       buf[1] = gc2145_svga[i].val;
+                       if (gc2145_svga[i].val == 0xff &&
+                         gc2145_svga[i].addr == 0xff) {
+                               pr_info("success in gc2145_svga.\n");
+                               break;
+                       }
+                       if ((i2c_put_byte_add8(client, buf, 2)) < 0) {
+                               pr_err("fail in gc2145_svga.\n");
+                               return;
+                       }
+                       i++;
+               }
+               gc2145_frmintervals_active.numerator = 1;
+               gc2145_frmintervals_active.denominator = 15;
+               GC2145_h_active = 800;
+               GC2145_v_active = 600;
+               mdelay(80);
+       } else if (width * height >= 1200 * 1600) {
+               buf[0] = 0xfe;
+               buf[1] = 0x00;
+               i2c_put_byte_add8(client, buf, 2);
+
+               buf[0] = 0xb6;
+               buf[1] = 0x00;
+               i2c_put_byte_add8(client, buf, 2);
+
+               buf[0] = 0x03;
+               value = i2c_get_byte_add8(client, 0x03);
+               shutter_l = value;
+               /*printk(KERN_INFO"set camera 0x03=0x%x\n", value);*/
+               pid |= (value << 8);
+
+               buf[0] = 0x04;
+               value = i2c_get_byte_add8(client, 0x04);
+               shutter_h = value;
+               /*printk(KERN_INFO"set camera 0x04=0x%x\n", value);*/
+               pid |= (value & 0x1f);
+
+               shutter = pid;
+               /*printk(KERN_INFO "set camera shutter=0x%x\n", shutter);*/
+
+               while (1) {
+                       buf[0] = gc2145_uxga[i].addr;
+                       buf[1] = gc2145_uxga[i].val;
+                       if (gc2145_uxga[i].val == 0xff &&
+                           gc2145_uxga[i].addr == 0xff) {
+                               pr_info("gc2145_write_regs success in gc2145_uxga.\n");
+                               break;
+                       }
+                       if ((i2c_put_byte_add8(client, buf, 2)) < 0) {
+                               pr_err("fail in gc2145_uxga.\n");
+                               return;
+                       }
+                       i++;
+               }
+
+               shutter = shutter / 2;
+               if (shutter < 1)
+                       shutter = 1;
+
+               buf[0] = 0x03;
+               buf[1] = ((shutter >> 8) & 0xff);
+               i2c_put_byte_add8(client, buf, 2);
+
+               buf[0] = 0x04;
+               buf[1] = (shutter & 0x1f);
+               i2c_put_byte_add8(client, buf, 2);
+
+               gc2145_frmintervals_active.denominator = 5;
+               gc2145_frmintervals_active.numerator = 1;
+               GC2145_h_active = 1600;
+               GC2145_v_active = 1200;
+               mdelay(130);
+       }
+       set_flip(dev);
+}    /* GC2145_set_resolution */
+
+unsigned char v4l_2_gc2145(int val)
+{
+       int ret = val / 0x20;
+
+       if (ret < 4)
+               return ret * 0x20 + 0x80;
+       else if (ret < 8)
+               return ret * 0x20 + 0x20;
+       else
+               return 0;
+}
+
+static int convert_canvas_index(unsigned int v4l2_format,
+                               unsigned int start_canvas)
+{
+       int canvas = start_canvas;
+
+       switch (v4l2_format) {
+       case V4L2_PIX_FMT_RGB565X:
+       case V4L2_PIX_FMT_VYUY:
+               canvas = start_canvas;
+               break;
+       case V4L2_PIX_FMT_YUV444:
+       case V4L2_PIX_FMT_BGR24:
+       case V4L2_PIX_FMT_RGB24:
+               canvas = start_canvas;
+               break;
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV21:
+               canvas = start_canvas | ((start_canvas + 1) << 8);
+               break;
+       case V4L2_PIX_FMT_YVU420:
+       case V4L2_PIX_FMT_YUV420:
+               if (v4l2_format == V4L2_PIX_FMT_YUV420)
+                       canvas = start_canvas | ((start_canvas + 1) << 8) |
+                               ((start_canvas + 2) << 16);
+               else
+                       canvas = start_canvas | ((start_canvas + 2) << 8) |
+                               ((start_canvas + 1) << 16);
+               break;
+       default:
+               break;
+       }
+       return canvas;
+}
+
+static int gc2145_setting(struct gc2145_device *dev, int PROP_ID, int value)
+{
+       int ret = 0;
+       /* unsigned char cur_val; */
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+
+       if (!dev->vminfo.isused)
+               return 0;
+       /*here register not finished */
+       switch (PROP_ID)  {
+
+       case V4L2_CID_BRIGHTNESS:
+               dprintk(dev, 1, "setting brightned:%d\n", v4l_2_gc2145(value));
+               ret = i2c_put_byte_add8_new(client, 0xdc, v4l_2_gc2145(value));
+               break;
+       case V4L2_CID_CONTRAST:
+               ret = i2c_put_byte_add8_new(client, 0xde, value);
+               break;
+       case V4L2_CID_SATURATION:
+               ret = i2c_put_byte_add8_new(client, 0xd9, value);
+               break;
+       case V4L2_CID_DO_WHITE_BALANCE:
+               if (gc2145_qctrl[0].default_value != value) {
+                       gc2145_qctrl[0].default_value = value;
+                       GC2145_set_param_wb(dev, value);
+                       pr_info("set camera  white_balance=%d.\n ",
+                               value);
+               }
+               break;
+       case V4L2_CID_EXPOSURE:
+               if (gc2145_qctrl[1].default_value != value) {
+                       gc2145_qctrl[1].default_value = value;
+                       GC2145_set_param_exposure(dev, value);
+                       pr_info("set camera  exposure=%d.\n",
+                               value);
+               }
+               break;
+       case V4L2_CID_COLORFX:
+               if (gc2145_qctrl[2].default_value != value) {
+                       gc2145_qctrl[2].default_value = value;
+                       /* GC2145_set_param_effect(dev,value); */
+                       pr_info("set camera  effect=%d.\n",
+                               value);
+               }
+               break;
+       case V4L2_CID_WHITENESS:
+               if (gc2145_qctrl[3].default_value != value) {
+                       gc2145_qctrl[3].default_value = value;
+                       pr_info("@@@SP_000:GC2145_set_param_banding,value=%d\n",
+                               value);
+                       GC2145_set_param_banding(dev, value);
+                       pr_info("@@@SP_111:gc2145_night_or_normal = %d",
+                               gc2145_night_or_normal);
+                       GC2145_set_night_mode(dev, gc2145_night_or_normal);
+                       pr_info("set camera  banding=%d.\n",
+                               value);
+               }
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               if (gc2145_qctrl[4].default_value != value) {
+                       gc2145_qctrl[4].default_value = value;
+                       pr_info("@@@SP_222:GC2145_set_night_mode,night mode=%d\n",
+                               value);
+                       pr_info("@@@SP_333:gc2145_night_or_normal = %d",
+                               gc2145_night_or_normal);
+                       GC2145_set_night_mode(dev, value);
+                       pr_info("set camera  scene mode=%d.\n",
+                               value);
+               }
+               break;
+       case V4L2_CID_HFLIP:    /* set flip on H. */
+               value = value & 0x3;
+               if (gc2145_qctrl[5].default_value != value) {
+                       gc2145_qctrl[5].default_value = value;
+                       pr_info(" set camera  h filp =%d.\n ", value);
+               }
+               break;
+       case V4L2_CID_VFLIP:    /* set flip on V. */
+               break;
+       case V4L2_CID_ZOOM_ABSOLUTE:
+               if (gc2145_qctrl[7].default_value != value)
+                       gc2145_qctrl[7].default_value = value;
+               break;
+       case V4L2_CID_ROTATE:
+               if (gc2145_qctrl[8].default_value != value) {
+                       gc2145_qctrl[8].default_value = value;
+                       pr_info(" set camera  rotate =%d.\n ", value);
+               }
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       return ret;
+}
+
+static void power_down_gc2145(struct gc2145_device *dev)
+{
+
+}
+
+/*
+ *------------------------------------------------------------------
+ *   DMA and thread functions
+ *  ------------------------------------------------------------------
+ */
+
+#define TSTAMP_MIN_Y    24
+#define TSTAMP_MAX_Y    (TSTAMP_MIN_Y + 15)
+#define TSTAMP_INPUT_X  10
+#define TSTAMP_MIN_X    (54 + TSTAMP_INPUT_X)
+
+static void gc2145_fillbuff(struct gc2145_fh *fh, struct gc2145_buffer *buf)
+{
+       int ret;
+       void *vbuf;
+       struct vm_output_para para = {0};
+       struct gc2145_device *dev = fh->dev;
+
+       if (dev->vminfo.mem_alloc_succeed)
+               vbuf = (void *)videobuf_to_res(&buf->vb);
+       else
+               vbuf = videobuf_to_vmalloc(&buf->vb);
+       dprintk(dev, 1, "%s\n", __func__);
+       if (!vbuf)
+               return;
+       /*  0x18221223 indicate the memory type is MAGIC_VMAL_MEM*/
+       if (dev->vminfo.mem_alloc_succeed) {
+               if (buf->canvas_id == 0)
+                       buf->canvas_id = convert_canvas_index(fh->fmt->fourcc,
+                     CAMERA_USER_CANVAS_INDEX + buf->vb.i * 3);
+               para.v4l2_memory = MAGIC_RE_MEM;
+       } else
+               para.v4l2_memory = MAGIC_VMAL_MEM;
+       para.mirror = gc2145_qctrl[5].default_value & 3;/* not set */
+       para.v4l2_format = fh->fmt->fourcc;
+       para.zoom = gc2145_qctrl[7].default_value;
+       para.angle = gc2145_qctrl[8].default_value;
+       para.vaddr = (uintptr_t)vbuf;
+       /* para.ext_canvas = buf->canvas_id; */
+       para.ext_canvas = 0;
+       para.width = buf->vb.width;
+       para.height = buf->vb.height;
+       dev->vminfo.vdin_id = dev->cam_info.vdin_path;
+       ret = vm_fill_this_buffer(&buf->vb, &para, &dev->vminfo);
+       /*if the vm is not used by sensor ,*/
+       /*we let vm_fill_this_buffer() return -2*/
+       if (ret == -2)
+               msleep(40);
+       buf->vb.state = VIDEOBUF_DONE;
+}
+
+static void gc2145_thread_tick(struct gc2145_fh *fh)
+{
+       struct gc2145_buffer *buf;
+       struct gc2145_device *dev = fh->dev;
+       struct gc2145_dmaqueue *dma_q = &dev->vidq;
+
+       unsigned long flags = 0;
+
+       dprintk(dev, 1, "Thread tick\n");
+       if (!fh->stream_on) {
+               dprintk(dev, 1, "sensor doesn't stream on\n");
+               return;
+       }
+       spin_lock_irqsave(&dev->slock, flags);
+       if (list_empty(&dma_q->active)) {
+               dprintk(dev, 1, "No active queue to serve\n");
+               goto unlock;
+       }
+
+       buf = list_entry(dma_q->active.next,
+                        struct gc2145_buffer, vb.queue);
+       dprintk(dev, 1, "%s\n", __func__);
+       dprintk(dev, 1, "list entry get buf is %p\n", buf);
+
+       if (!(fh->f_flags & O_NONBLOCK)) {
+               /* Nobody is waiting on this buffer, return */
+               if (!waitqueue_active(&buf->vb.done))
+                       goto unlock;
+       }
+       buf->vb.state = VIDEOBUF_ACTIVE;
+
+       list_del(&buf->vb.queue);
+
+       do_gettimeofday(&buf->vb.ts);
+
+       /* Fill buffer */
+       spin_unlock_irqrestore(&dev->slock, flags);
+       gc2145_fillbuff(fh, buf);
+       dprintk(dev, 1, "filled buffer %p\n", buf);
+
+       wake_up(&buf->vb.done);
+       dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+       return;
+unlock:
+       spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+#define frames_to_ms(frames)   \
+       ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
+
+static void gc2145_sleep(struct gc2145_fh *fh)
+{
+       struct gc2145_device *dev = fh->dev;
+       struct gc2145_dmaqueue *dma_q = &dev->vidq;
+
+       DECLARE_WAITQUEUE(wait, current);
+
+       dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
+               (unsigned long)dma_q);
+
+       add_wait_queue(&dma_q->wq, &wait);
+       if (kthread_should_stop())
+               goto stop_task;
+
+       /* Calculate time to wake up */
+       /* timeout = msecs_to_jiffies(frames_to_ms(1)); */
+
+       gc2145_thread_tick(fh);
+
+       schedule_timeout_interruptible(2);
+
+stop_task:
+       remove_wait_queue(&dma_q->wq, &wait);
+       try_to_freeze();
+}
+
+static int gc2145_thread(void *data)
+{
+       struct gc2145_fh  *fh = data;
+       struct gc2145_device *dev = fh->dev;
+
+       dprintk(dev, 1, "thread started\n");
+
+       set_freezable();
+
+       for (; ;) {
+               gc2145_sleep(fh);
+
+               if (kthread_should_stop())
+                       break;
+       }
+       dprintk(dev, 1, "thread: exit\n");
+       return 0;
+}
+
+static int gc2145_start_thread(struct gc2145_fh *fh)
+{
+       struct gc2145_device *dev = fh->dev;
+       struct gc2145_dmaqueue *dma_q = &dev->vidq;
+
+       dma_q->frame = 0;
+       dma_q->ini_jiffies = jiffies;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       dma_q->kthread = kthread_run(gc2145_thread, fh, "gc2145");
+
+       if (IS_ERR(dma_q->kthread)) {
+               v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+               return PTR_ERR(dma_q->kthread);
+       }
+       /* Wakes thread */
+       wake_up_interruptible(&dma_q->wq);
+
+       dprintk(dev, 1, "returning from %s\n", __func__);
+       return 0;
+}
+
+static void gc2145_stop_thread(struct gc2145_dmaqueue  *dma_q)
+{
+       struct gc2145_device *dev =
+               container_of(dma_q, struct gc2145_device, vidq);
+
+       dprintk(dev, 1, "%s\n", __func__);
+       /* shutdown control thread */
+       if (dma_q->kthread) {
+               kthread_stop(dma_q->kthread);
+               dma_q->kthread = NULL;
+       }
+}
+
+/*
+ *------------------------------------------------------------------
+ *    Videobuf operations
+ *  ------------------------------------------------------------------
+ */
+
+static int
+vmall_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+                  unsigned int *size)
+{
+       struct gc2145_fh  *fh = vq->priv_data;
+       struct gc2145_device *dev  = fh->dev;
+       /* int bytes = fh->fmt->depth >> 3 ; */
+       *size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       if (*count == 0)
+               *count = 32;
+
+       while (*size * *count > vid_limit * 1024 * 1024)
+               (*count)--;
+
+       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
+               *count, *size);
+
+       return 0;
+}
+
+static int
+res_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+                unsigned int *size)
+{
+       struct videobuf_res_privdata *res = vq->priv_data;
+       struct gc2145_fh *fh = container_of(res, struct gc2145_fh, res);
+       struct gc2145_device *dev  = fh->dev;
+       /* int bytes = fh->fmt->depth >> 3 ; */
+       int height = fh->height;
+
+       if (height == 1080)
+               height = 1088;
+       *size = (fh->width * height * fh->fmt->depth) >> 3;
+       if (*count == 0)
+               *count = 32;
+
+       while (*size * *count > vid_limit * 1024 * 1024)
+               (*count)--;
+
+       dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
+               *count, *size);
+
+       return 0;
+}
+
+static void free_vmall_buffer(struct videobuf_queue *vq,
+                             struct gc2145_buffer *buf)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+
+       fh = vq->priv_data;
+       dev = fh->dev;
+
+       dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
+
+       videobuf_waiton(vq, &buf->vb, 0, 0);
+       if (in_interrupt())
+               WARN_ON(1);
+       videobuf_vmalloc_free(&buf->vb);
+       dprintk(dev, 1, "free_vmall_buffer: freed\n");
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void free_res_buffer(struct videobuf_queue *vq,
+                           struct gc2145_buffer *buf)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct videobuf_res_privdata *res = vq->priv_data;
+
+       fh = container_of(res, struct gc2145_fh, res);
+       dev = fh->dev;
+
+       dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
+
+       videobuf_waiton(vq, &buf->vb, 0, 0);
+       if (in_interrupt())
+               WARN_ON(1);
+       videobuf_res_free(vq, &buf->vb);
+       dprintk(dev, 1, "free_res_buffer: freed\n");
+       buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+#define norm_maxw() 1920
+#define norm_maxh() 1600
+static int
+vmall_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+                    enum v4l2_field field)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct gc2145_buffer *buf;
+       int rc;
+
+       fh  = vq->priv_data;
+       dev = fh->dev;
+       buf = container_of(vb, struct gc2145_buffer, vb);
+       /* int bytes = fh->fmt->depth >> 3 ; */
+       dprintk(dev, 1, "%s, field=%d\n", __func__, field);
+
+       WARN_ON(fh->fmt == NULL);
+
+       if (fh->width  < 48 || fh->width  > norm_maxw() ||
+           fh->height < 32 || fh->height > norm_maxh())
+               return -EINVAL;
+
+       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       /* These properties only change when queue is idle, see s_fmt */
+       buf->fmt       = fh->fmt;
+       buf->vb.width  = fh->width;
+       buf->vb.height = fh->height;
+       buf->vb.field  = field;
+
+       /* precalculate_bars(fh); */
+
+       if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc < 0)
+                       goto fail;
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+
+       return 0;
+
+fail:
+       free_vmall_buffer(vq, buf);
+       return rc;
+}
+
+static int
+res_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+                  enum v4l2_field field)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct gc2145_buffer *buf;
+       int rc;
+       struct videobuf_res_privdata *res = vq->priv_data;
+
+       fh = container_of(res, struct gc2145_fh, res);
+       dev = fh->dev;
+       buf = container_of(vb, struct gc2145_buffer, vb);
+       dprintk(dev, 1, "%s, field=%d\n", __func__, field);
+
+       WARN_ON(fh->fmt == NULL);
+
+       if (fh->width  < 48 || fh->width  > norm_maxw() ||
+           fh->height < 32 || fh->height > norm_maxh())
+               return -EINVAL;
+
+       buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+       if (buf->vb.baddr != 0 &&  buf->vb.bsize < buf->vb.size)
+               return -EINVAL;
+
+       /* These properties only change when queue is idle, see s_fmt */
+       buf->fmt       = fh->fmt;
+       buf->vb.width  = fh->width;
+       buf->vb.height = fh->height;
+       buf->vb.field  = field;
+
+       /* precalculate_bars(fh); */
+
+       if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+               rc = videobuf_iolock(vq, &buf->vb, NULL);
+               if (rc < 0)
+                       goto fail;
+       }
+
+       buf->vb.state = VIDEOBUF_PREPARED;
+
+       return 0;
+
+fail:
+       free_res_buffer(vq, buf);
+       return rc;
+}
+
+static void
+res_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct gc2145_dmaqueue *vidq;
+       struct gc2145_buffer *buf  = container_of(vb, struct gc2145_buffer, vb);
+       struct videobuf_res_privdata *res = vq->priv_data;
+
+       fh = container_of(res, struct gc2145_fh, res);
+       dev = fh->dev;
+       vidq = &dev->vidq;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void
+vmall_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct gc2145_dmaqueue *vidq;
+       struct gc2145_buffer *buf  = container_of(vb, struct gc2145_buffer, vb);
+
+       fh = vq->priv_data;
+       dev = fh->dev;
+       vidq = &dev->vidq;
+
+       dprintk(dev, 1, "%s\n", __func__);
+       buf->vb.state = VIDEOBUF_QUEUED;
+       list_add_tail(&buf->vb.queue, &vidq->active);
+}
+
+static void res_buffer_release(struct videobuf_queue *vq,
+                              struct videobuf_buffer *vb)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct gc2145_buffer   *buf  =
+               container_of(vb, struct gc2145_buffer, vb);
+       struct videobuf_res_privdata *res = vq->priv_data;
+
+       fh = container_of(res, struct gc2145_fh, res);
+       dev = (struct gc2145_device *)fh->dev;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       free_res_buffer(vq, buf);
+}
+
+static void vmall_buffer_release(struct videobuf_queue *vq,
+                                struct videobuf_buffer *vb)
+{
+       struct gc2145_fh *fh;
+       struct gc2145_device *dev;
+       struct gc2145_buffer   *buf  =
+               container_of(vb, struct gc2145_buffer, vb);
+       fh   = vq->priv_data;
+       dev = (struct gc2145_device *)fh->dev;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       free_vmall_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops gc2145_video_vmall_qops = {
+       .buf_setup      = vmall_buffer_setup,
+       .buf_prepare    = vmall_buffer_prepare,
+       .buf_queue      = vmall_buffer_queue,
+       .buf_release    = vmall_buffer_release,
+};
+
+static struct videobuf_queue_ops gc2145_video_res_qops = {
+       .buf_setup      = res_buffer_setup,
+       .buf_prepare    = res_buffer_prepare,
+       .buf_queue      = res_buffer_queue,
+       .buf_release    = res_buffer_release,
+};
+
+/*
+ *------------------------------------------------------------------
+ *    IOCTL vidioc handling
+ *  ------------------------------------------------------------------
+ */
+
+static int vidioc_querycap(struct file *file, void  *priv,
+                          struct v4l2_capability *cap)
+{
+       struct gc2145_fh  *fh  = priv;
+       struct gc2145_device *dev = fh->dev;
+
+       strcpy(cap->driver, "gc2145");
+       strcpy(cap->card, "gc2145.canvas");
+       if (dev->cam_info.front_back == 0)
+               strcat(cap->card, "back");
+       else
+               strcat(cap->card, "front");
+
+       strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
+       cap->version = GC2145_CAMERA_VERSION;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
+                               | V4L2_CAP_READWRITE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       struct gc2145_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(formats))
+               return -EINVAL;
+
+       fmt = &formats[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
+       return 0;
+}
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+                                     struct v4l2_frmivalenum *fival)
+{
+       unsigned int k;
+
+       if (fival->index > ARRAY_SIZE(gc2145_frmivalenum))
+               return -EINVAL;
+
+       for (k = 0; k < ARRAY_SIZE(gc2145_frmivalenum); k++) {
+               if ((fival->index == gc2145_frmivalenum[k].index) &&
+                   (fival->pixel_format ==
+                                       gc2145_frmivalenum[k].pixel_format) &&
+                   (fival->width == gc2145_frmivalenum[k].width) &&
+                   (fival->height == gc2145_frmivalenum[k].height)) {
+                       memcpy(fival, &gc2145_frmivalenum[k],
+                                       sizeof(struct v4l2_frmivalenum));
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct gc2145_fh *fh = priv;
+
+       f->fmt.pix.width        = fh->width;
+       f->fmt.pix.height       = fh->height;
+       f->fmt.pix.field        = fh->vb_vidq.field;
+       f->fmt.pix.pixelformat  = fh->fmt->fourcc;
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fh->fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct gc2145_fh  *fh  = priv;
+       struct gc2145_device *dev = fh->dev;
+       struct gc2145_fmt *fmt;
+       enum v4l2_field field;
+       unsigned int maxw, maxh;
+
+       fmt = get_format(f);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
+                       f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       field = f->fmt.pix.field;
+
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_INTERLACED;
+       else if (field != V4L2_FIELD_INTERLACED) {
+               dprintk(dev, 1, "Field type invalid.\n");
+               return -EINVAL;
+       }
+
+       maxw  = norm_maxw();
+       maxh  = norm_maxh();
+
+       f->fmt.pix.field = field;
+       v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+                             &f->fmt.pix.height, 32, maxh, 0, 0);
+       f->fmt.pix.bytesperline =
+               (f->fmt.pix.width * fmt->depth) >> 3;
+       f->fmt.pix.sizeimage =
+               f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct gc2145_fh *fh = priv;
+       struct videobuf_queue *q = &fh->vb_vidq;
+       struct gc2145_device *dev = fh->dev;
+       int ret;
+
+       f->fmt.pix.width = (f->fmt.pix.width +
+                                       (CANVAS_WIDTH_ALIGN - 1)) &
+                                       (~(CANVAS_WIDTH_ALIGN - 1));
+       if ((f->fmt.pix.pixelformat == V4L2_PIX_FMT_YVU420) ||
+           (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420))
+               f->fmt.pix.width = (f->fmt.pix.width +
+                                               (CANVAS_WIDTH_ALIGN * 2 - 1)) &
+                                               (~(CANVAS_WIDTH_ALIGN * 2 - 1));
+
+       ret = vidioc_try_fmt_vid_cap(file, fh, f);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&q->vb_lock);
+
+       if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+               dprintk(fh->dev, 1, "%s queue busy\n", __func__);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       fh->fmt           = get_format(f);
+       fh->width         = f->fmt.pix.width;
+       fh->height        = f->fmt.pix.height;
+       fh->vb_vidq.field = f->fmt.pix.field;
+       fh->type          = f->type;
+#if 0
+       set_flip(dev);
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+               vidio_set_fmt_ticks = 1;
+               GC2145_set_resolution(dev, fh->height, fh->width);
+       } else if (vidio_set_fmt_ticks == 1)
+               GC2145_set_resolution(dev, fh->height, fh->width);
+#else
+       GC2145_set_resolution(dev, fh->height, fh->width);
+#endif
+       ret = 0;
+out:
+       mutex_unlock(&q->vb_lock);
+
+       return ret;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *parms)
+{
+       struct gc2145_fh *fh = priv;
+       struct gc2145_device *dev = fh->dev;
+       struct v4l2_captureparm *cp = &parms->parm.capture;
+
+       dprintk(dev, 3, "vidioc_g_parm\n");
+       if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       memset(cp, 0, sizeof(struct v4l2_captureparm));
+       cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+       cp->timeperframe = gc2145_frmintervals_active;
+       pr_debug("g_parm,deno=%d, numerator=%d\n",
+                       cp->timeperframe.denominator,
+                       cp->timeperframe.numerator);
+       return 0;
+}
+
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *p)
+{
+       struct gc2145_fh  *fh = priv;
+
+       return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct gc2145_fh  *fh = priv;
+       int ret = videobuf_querybuf(&fh->vb_vidq, p);
+
+       if (get_cpu_type() == MESON_CPU_MAJOR_ID_M8) {
+               if (ret == 0)
+                       p->reserved  = convert_canvas_index(fh->fmt->fourcc,
+                                       CAMERA_USER_CANVAS_INDEX +
+                                       p->index * 3);
+               else
+                       p->reserved = 0;
+       }
+       return ret;
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct gc2145_fh *fh = priv;
+
+       return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+       struct gc2145_fh  *fh = priv;
+
+       return videobuf_dqbuf(&fh->vb_vidq, p,
+                              file->f_flags & O_NONBLOCK);
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+       struct gc2145_fh  *fh = priv;
+
+       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
+}
+#endif
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct gc2145_fh  *fh = priv;
+       struct vdin_parm_s para;
+       unsigned int vdin_path;
+       int ret = 0;
+
+       pr_info("vidioc_streamon+++\n ");
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
+
+       memset(&para, 0, sizeof(para));
+       para.port  = TVIN_PORT_CAMERA;
+       para.fmt = TVIN_SIG_FMT_MAX;
+       para.frame_rate = gc2145_frmintervals_active.denominator;
+       para.h_active = GC2145_h_active;
+       para.v_active = GC2145_v_active;
+       para.hsync_phase = 1;
+       para.vsync_phase = 1;
+       para.hs_bp = 0;
+       para.vs_bp = 3;
+       para.bt_path = fh->dev->cam_info.bt_path;
+       vdin_path = fh->dev->cam_info.vdin_path;
+       para.cfmt = TVIN_YUV422;
+       para.dfmt = TVIN_NV21;
+       para.scan_mode = TVIN_SCAN_MODE_PROGRESSIVE;
+
+       if (is_first_time_open == 0) {
+               para.skip_count =  4;
+               is_first_time_open = 1;
+       } else
+               para.skip_count =  0;
+
+       ret =  videobuf_streamon(&fh->vb_vidq);
+       if (ret == 0) {
+               if (fh->dev->vminfo.isused) {
+                       vops->start_tvin_service(vdin_path, &para);
+                       fh->stream_on = 1;
+               }
+       }
+
+       return ret;
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+       struct gc2145_fh  *fh = priv;
+       unsigned int vdin_path;
+       int ret = 0;
+
+       pr_info("vidioc_streamoff+++\n ");
+       vdin_path = fh->dev->cam_info.vdin_path;
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       if (i != fh->type)
+               return -EINVAL;
+       ret = videobuf_streamoff(&fh->vb_vidq);
+       if (ret == 0) {
+               if (fh->dev->vminfo.isused)
+                       vops->stop_tvin_service(vdin_path);
+               fh->stream_on        = 0;
+       }
+       return ret;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       int ret = 0, i = 0;
+       struct gc2145_fmt *fmt = NULL;
+       struct v4l2_frmsize_discrete *frmsize = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(formats); i++) {
+               if (formats[i].fourcc == fsize->pixel_format) {
+                       fmt = &formats[i];
+                       break;
+               }
+       }
+       if (fmt == NULL)
+               return -EINVAL;
+       if ((fmt->fourcc == V4L2_PIX_FMT_NV21)
+           || (fmt->fourcc == V4L2_PIX_FMT_NV12)
+           || (fmt->fourcc == V4L2_PIX_FMT_YVU420)
+           || (fmt->fourcc == V4L2_PIX_FMT_YUV420)) {
+               if (fsize->index >= ARRAY_SIZE(gc2145_prev_resolution))
+                       return -EINVAL;
+               frmsize = &gc2145_prev_resolution[fsize->index];
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete.width = frmsize->width;
+               fsize->discrete.height = frmsize->height;
+       } else if (fmt->fourcc == V4L2_PIX_FMT_RGB24) {
+               if (fsize->index >= ARRAY_SIZE(gc2145_pic_resolution))
+                       return -EINVAL;
+               frmsize = &gc2145_pic_resolution[fsize->index];
+               fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+               fsize->discrete.width = frmsize->width;
+               fsize->discrete.height = frmsize->height;
+       }
+       return ret;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
+{
+       return 0;
+}
+
+/* only one input in this sample driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+                            struct v4l2_input *inp)
+{
+       /* if  (inp->index >= NUM_INPUTS) */
+       /* return -EINVAL; */
+
+       inp->type = V4L2_INPUT_TYPE_CAMERA;
+       inp->std = V4L2_STD_525_60;
+       sprintf(inp->name, "Camera %u", inp->index);
+
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct gc2145_fh *fh = priv;
+       struct gc2145_device *dev = fh->dev;
+
+       *i = dev->input;
+
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct gc2145_fh *fh = priv;
+       struct gc2145_device *dev = fh->dev;
+
+       /* if  (i >= NUM_INPUTS) */
+       /* return -EINVAL; */
+
+       dev->input = i;
+       /* precalculate_bars(fh); */
+
+       return 0;
+}
+
+/* --- controls ---------------------------------------------- */
+static int vidioc_queryctrl(struct file *file, void *priv,
+                           struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(gc2145_qctrl); i++)
+               if (qc->id && qc->id == gc2145_qctrl[i].id) {
+                       memcpy(qc, &(gc2145_qctrl[i]),
+                              sizeof(*qc));
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *ctrl)
+{
+       struct gc2145_fh *fh = priv;
+       struct gc2145_device *dev = fh->dev;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(gc2145_qctrl); i++)
+               if (ctrl->id == gc2145_qctrl[i].id) {
+                       ctrl->value = dev->qctl_regs[i];
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+                        struct v4l2_control *ctrl)
+{
+       struct gc2145_fh *fh = priv;
+       struct gc2145_device *dev = fh->dev;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(gc2145_qctrl); i++)
+               if (ctrl->id == gc2145_qctrl[i].id) {
+                       if (ctrl->value < gc2145_qctrl[i].minimum ||
+                           ctrl->value > gc2145_qctrl[i].maximum ||
+                           gc2145_setting(dev, ctrl->id, ctrl->value) < 0)
+                               return -ERANGE;
+                       dev->qctl_regs[i] = ctrl->value;
+                       return 0;
+               }
+       return -EINVAL;
+}
+
+/*
+ *------------------------------------------------------------------
+ *   File operations for the device
+ * -----------------------------------------------------------------
+ */
+
+static int gc2145_open(struct file *file)
+{
+       struct gc2145_device *dev = video_drvdata(file);
+       struct gc2145_fh *fh = NULL;
+       int retval = 0;
+
+       dev->vminfo.vdin_id = dev->cam_info.vdin_path;
+       dev->vminfo.bt_path_count = dev->cam_info.bt_path_count;
+
+#if CONFIG_CMA
+       vm_init_resource(16 * SZ_1M, &dev->vminfo);
+#endif
+       if (dev->vminfo.isused) {
+               pr_info("%s, front_back = %d\n",
+                 __func__, dev->cam_info.front_back);
+               aml_cam_init(&dev->cam_info);
+       }
+
+       GC2145_init_regs(dev);
+       msleep(40);
+       mutex_lock(&dev->mutex);
+       dev->users++;
+       if (dev->users > 1) {
+               dev->users--;
+               pr_err("gc2145 device is opened, device is busy\n");
+               mutex_unlock(&dev->mutex);
+               return -EBUSY;
+       }
+
+       dprintk(dev, 1, "open %s type=%s users=%d\n",
+               video_device_node_name(dev->vdev),
+               v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       init_waitqueue_head(&dev->vidq.wq);
+       spin_lock_init(&dev->slock);
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (fh == NULL) {
+               dev->users--;
+               retval = -ENOMEM;
+       }
+       mutex_unlock(&dev->mutex);
+
+       if (retval)
+               return retval;
+
+#ifdef CONFIG_HAS_WAKELOCK
+       wake_lock(&(dev->wake_lock));
+#endif
+
+       file->private_data = fh;
+       fh->dev      = dev;
+
+       fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fh->fmt      = &formats[0];
+       fh->width    = 1600;/* 640//zyy */
+       fh->height   = 1198;/* 1200;//480 */
+       fh->stream_on = 0;
+       fh->f_flags  = file->f_flags;
+       /* Resets frame counters */
+       /*dev->jiffies = jiffies;*/
+
+       /* TVIN_SIG_FMT_CAMERA_640X480P_30Hz, */
+       /* TVIN_SIG_FMT_CAMERA_800X600P_30Hz, */
+       /* TVIN_SIG_FMT_CAMERA_1024X768P_30Hz, // 190 */
+       /* TVIN_SIG_FMT_CAMERA_1920X1080P_30Hz, */
+       /* TVIN_SIG_FMT_CAMERA_1280X720P_30Hz, */
+
+       if (dev->vminfo.mem_alloc_succeed) {
+               fh->res.start = dev->vminfo.buffer_start;
+               fh->res.end = dev->vminfo.buffer_start +
+                                               dev->vminfo.vm_buf_size - 1;
+               fh->res.magic = MAGIC_RE_MEM;
+               fh->res.priv = NULL;
+               videobuf_queue_res_init(&fh->vb_vidq,
+                       &gc2145_video_res_qops, NULL,
+                       &dev->slock, fh->type,
+                       V4L2_FIELD_INTERLACED,
+                       sizeof(struct gc2145_buffer),
+                       (void *)&fh->res, NULL);
+       } else {
+               videobuf_queue_vmalloc_init(&fh->vb_vidq,
+                               &gc2145_video_vmall_qops, NULL,
+                               &dev->slock, fh->type,
+                               V4L2_FIELD_INTERLACED,
+                               sizeof(struct gc2145_buffer), fh, NULL);
+       }
+
+       gc2145_start_thread(fh);
+       gc2145_have_open = 1;
+       return 0;
+}
+
+static ssize_t
+gc2145_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+{
+       struct gc2145_fh *fh = file->private_data;
+
+       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+                                           file->f_flags & O_NONBLOCK);
+       }
+       return 0;
+}
+
+static unsigned int
+gc2145_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct gc2145_fh        *fh = file->private_data;
+       struct gc2145_device       *dev = fh->dev;
+       struct videobuf_queue *q = &fh->vb_vidq;
+
+       dprintk(dev, 1, "%s\n", __func__);
+
+       if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return POLLERR;
+
+       return videobuf_poll_stream(file, q, wait);
+}
+
+static int gc2145_close(struct file *file)
+{
+       struct gc2145_fh         *fh = file->private_data;
+       struct gc2145_device *dev       = fh->dev;
+       struct gc2145_dmaqueue *vidq = &dev->vidq;
+       struct video_device  *vdev = video_devdata(file);
+       unsigned int vdin_path;
+
+       vdin_path = fh->dev->cam_info.vdin_path;
+       gc2145_have_open = 0;
+       is_first_time_open = 0;
+
+       gc2145_stop_thread(vidq);
+       videobuf_stop(&fh->vb_vidq);
+       if (fh->stream_on) {
+               if (dev->vminfo.isused) {
+                       pr_info("%s, vdin_path = %d\n",
+                          __func__, vdin_path);
+                       vops->stop_tvin_service(vdin_path);
+               }
+       }
+       videobuf_mmap_free(&fh->vb_vidq);
+       kfree(fh);
+
+       mutex_lock(&dev->mutex);
+       dev->users--;
+       mutex_unlock(&dev->mutex);
+
+       dprintk(dev, 1, "close called (dev=%s, users=%d)\n",
+               video_device_node_name(vdev), dev->users);
+#if 1
+       GC2145_h_active = 640; /* 800//zyy */
+       GC2145_v_active = 480; /* 1200;//600 */
+       gc2145_qctrl[0].default_value = 0;
+       gc2145_qctrl[1].default_value = 4;
+       gc2145_qctrl[2].default_value = 0;
+       gc2145_qctrl[3].default_value = 0;
+       gc2145_qctrl[4].default_value = 0;
+
+       gc2145_qctrl[5].default_value = 0;
+       gc2145_qctrl[7].default_value = 100;
+       gc2145_qctrl[8].default_value = 0;
+       gc2145_frmintervals_active.numerator = 1;
+       gc2145_frmintervals_active.denominator = 15;
+       power_down_gc2145(dev);
+#endif
+       aml_cam_uninit(&dev->cam_info);
+#ifdef CONFIG_HAS_WAKELOCK
+       wake_unlock(&(dev->wake_lock));
+#endif
+#ifdef CONFIG_CMA
+       vm_deinit_resource(&dev->vminfo);
+#endif
+       return 0;
+}
+
+static int gc2145_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct gc2145_fh  *fh = file->private_data;
+       struct gc2145_device *dev = fh->dev;
+       int ret;
+
+       dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+       ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+       dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+               (unsigned long)vma->vm_start,
+               (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+               ret);
+
+       return ret;
+}
+
+static const struct v4l2_file_operations gc2145_fops = {
+       .owner      = THIS_MODULE,
+       .open           = gc2145_open,
+       .release        = gc2145_close,
+       .read           = gc2145_read,
+       .poll       = gc2145_poll,
+       .unlocked_ioctl          = video_ioctl2, /* V4L2 ioctl handler */
+       .mmap           = gc2145_mmap,
+};
+
+static const struct v4l2_ioctl_ops gc2145_ioctl_ops = {
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_reqbufs       = vidioc_reqbufs,
+       .vidioc_querybuf      = vidioc_querybuf,
+       .vidioc_qbuf          = vidioc_qbuf,
+       .vidioc_dqbuf         = vidioc_dqbuf,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+       .vidioc_queryctrl     = vidioc_queryctrl,
+       .vidioc_querymenu     = vidioc_querymenu,
+       .vidioc_g_ctrl        = vidioc_g_ctrl,
+       .vidioc_s_ctrl        = vidioc_s_ctrl,
+       .vidioc_streamon      = vidioc_streamon,
+       .vidioc_streamoff     = vidioc_streamoff,
+       .vidioc_enum_framesizes = vidioc_enum_framesizes,
+       .vidioc_g_parm = vidioc_g_parm,
+       .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+       .vidiocgmbuf          = vidiocgmbuf,
+#endif
+};
+
+static struct video_device gc2145_template = {
+       .name       = "gc2145_v4l",
+       .fops           = &gc2145_fops,
+       .ioctl_ops  = &gc2145_ioctl_ops,
+       .release    = video_device_release,
+       .tvnorms    = V4L2_STD_525_60,
+};
+
+static const struct v4l2_subdev_core_ops gc2145_core_ops = {
+       /*.g_chip_ident = gc2145_g_chip_ident,*/
+};
+
+static const struct v4l2_subdev_ops gc2145_ops = {
+       .core = &gc2145_core_ops,
+};
+
+static ssize_t gc2145_show(struct device *dev, struct device_attribute *attr,
+                          char *_buf)
+{
+       return sprintf(_buf, "0x%02x=0x%02x\n", cur_reg, cur_val);
+}
+
+static u32 strtol(const char *nptr, int base)
+{
+       u32 ret;
+
+       if (!nptr || (base != 16 && base != 10 && base != 8)) {
+               pr_err("%s(): NULL pointer input\n", __func__);
+               return -1;
+       }
+       for (ret = 0; *nptr; nptr++) {
+               if ((base == 16 && *nptr >= 'A' && *nptr <= 'F') ||
+                   (base == 16 && *nptr >= 'a' && *nptr <= 'f') ||
+                   (base >= 10 && *nptr >= '0' && *nptr <= '9') ||
+                   (base >= 8  && *nptr >= '0' && *nptr <= '7')) {
+                       ret *= base;
+                       if (base == 16 && *nptr >= 'A' && *nptr <= 'F')
+                               ret += *nptr - 'A' + 10;
+                       else if (base == 16 && *nptr >= 'a' && *nptr <= 'f')
+                               ret += *nptr - 'a' + 10;
+                       else if (base >= 10 && *nptr >= '0' && *nptr <= '9')
+                               ret += *nptr - '0';
+                       else if (base >= 8 && *nptr >= '0' && *nptr <= '7')
+                               ret += *nptr - '0';
+               } else
+                       return ret;
+       }
+       return ret;
+}
+
+static ssize_t gc2145_store(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *_buf, size_t _count)
+{
+       const char *p = _buf;
+       u16 reg;
+       u8 val;
+
+       if (!strncmp(_buf, "get", strlen("get"))) {
+               p += strlen("get");
+               cur_reg = (u32)strtol(p, 16);
+               val = i2c_get_byte_add8(g_i2c_client, cur_reg);
+               pr_info("%s(): get 0x%04x=0x%02x\n",
+                               __func__, cur_reg, val);
+               cur_val = val;
+       } else if (!strncmp(_buf, "put", strlen("put"))) {
+               p += strlen("put");
+               reg = strtol(p, 16);
+               p = strchr(_buf, '=');
+               if (p) {
+                       ++p;
+                       val = strtol(p, 16);
+                       i2c_put_byte_add8_new(g_i2c_client, reg, val);
+                       pr_info("%s(): set 0x%04x=0x%02x\n",
+                               __func__, reg, val);
+               } else
+                       pr_info("%s(): Bad string format input!\n", __func__);
+       } else
+               pr_info("%s(): Bad string format input!\n", __func__);
+
+       return _count;
+}
+
+static ssize_t name_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *_buf)
+{
+       strcpy(_buf, "GC2145");
+       return 4;
+}
+
+static struct device *gc2145_dev;
+static struct class   *gc2145_class;
+static DEVICE_ATTR(gc2145, 0444, gc2145_show, gc2145_store);/*0666*/
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+#define  EMDOOR_DEBUG_GC2145    1
+#ifdef EMDOOR_DEBUG_GC2145
+unsigned int gc2145_reg_addr;
+static struct i2c_client *gc2145_client;
+
+static ssize_t gc2145_show_mine(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               char *buf)
+{
+       unsigned  char dat;
+
+       dat = i2c_get_byte_add8(gc2145_client, gc2145_reg_addr);
+       return sprintf(buf, "REG[0x%x]=0x%x\n", gc2145_reg_addr, dat);
+}
+
+static ssize_t gc2145_store_mine(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buf, size_t count)
+{
+       int tmp;
+       unsigned short reg;
+       unsigned char val;
+
+       tmp = kstrtoul(buf, 16, NULL);
+       /* sscanf(buf, "%du", &tmp); */
+       if (tmp < 0xff)
+               gc2145_reg_addr = tmp;
+       else {
+               reg = (tmp >> 8) & 0xFFFF; /* reg */
+               gc2145_reg_addr = reg;
+               val = tmp & 0xFF;        /* val */
+               i2c_put_byte_add8_new(gc2145_client, reg, val);
+       }
+
+       return count;
+}
+
+
+static struct kobj_attribute gc2145_attribute = __ATTR(gc2145, 0444,
+               gc2145_show_mine, gc2145_store_mine);
+
+
+static struct attribute *gc2145_attrs[] = {
+       &gc2145_attribute.attr,
+       NULL,
+};
+
+
+static const struct attribute_group gc2145_group = {
+       .attrs = gc2145_attrs,
+};
+#endif
+
+static int gc2145_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int err;
+       struct gc2145_device *t;
+       struct v4l2_subdev *sd;
+       struct aml_cam_info_s *plat_dat;
+       int ret;
+
+       vops = get_vdin_v4l2_ops();
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+               client->addr << 1, client->adapter->name);
+       t = kzalloc(sizeof(*t), GFP_KERNEL);
+       /* modify correct i2c addr--- 0x30 */
+       client->addr = 0x3c;
+       if (t == NULL) {
+               pr_err("%s, no memory", __func__);
+               return -ENOMEM;
+       }
+       snprintf(t->v4l2_dev.name, sizeof(t->v4l2_dev.name),
+               "%s-%03d", "gc2145", 0);
+       ret = v4l2_device_register(NULL, &t->v4l2_dev);
+       if (ret) {
+               pr_info("%s, v4l2 device register failed", __func__);
+               kfree(t);
+               kfree(client);
+               return ret;
+       }
+
+       sd = &t->sd;
+       v4l2_i2c_subdev_init(sd, client, &gc2145_ops);
+
+       plat_dat = (struct aml_cam_info_s *)client->dev.platform_data;
+       /* test if devices exist. */
+       memset(&t->vminfo, 0, sizeof(struct vm_init_s));
+       /* Now create a video4linux device */
+       mutex_init(&t->mutex);
+
+       /* Now create a video4linux device */
+       t->vdev = video_device_alloc();
+       if (t->vdev == NULL) {
+               kfree(t);
+               kfree(client);
+               return -ENOMEM;
+       }
+       memcpy(t->vdev, &gc2145_template, sizeof(*t->vdev));
+       t->vdev->v4l2_dev = &t->v4l2_dev;
+       video_set_drvdata(t->vdev, t);
+
+#ifdef CONFIG_HAS_WAKELOCK
+       wake_lock_init(&(t->wake_lock), WAKE_LOCK_SUSPEND, "gc2145");
+#endif
+
+       /* Register it */
+       if (plat_dat) {
+               memcpy(&t->cam_info, plat_dat, sizeof(struct aml_cam_info_s));
+               pr_info("%s, front_back = %d\n",
+                    __func__, plat_dat->front_back);
+               video_nr = plat_dat->front_back;
+       } else {
+               pr_err("camera gc2145: have no platform data\n");
+               kfree(t);
+               return -1;
+       }
+
+       t->cam_info.version = GC2145_DRIVER_VERSION;
+       if (aml_cam_info_reg(&t->cam_info) < 0)
+               pr_err("reg caminfo error\n");
+       err = video_register_device(t->vdev, VFL_TYPE_GRABBER, video_nr);
+       if (err < 0) {
+               video_device_release(t->vdev);
+               kfree(t);
+               return err;
+       }
+
+       gc2145_class = class_create(THIS_MODULE, "gc2145");
+       if (IS_ERR(gc2145_class)) {
+               pr_err("Create class gc2145 fail.\n");
+               return -ENOMEM;
+       }
+       gc2145_dev = device_create(gc2145_class, NULL,
+               MKDEV(0, 1), NULL, "dev");
+       device_create_file(gc2145_dev, &dev_attr_gc2145);
+       device_create_file(gc2145_dev, &dev_attr_name);
+
+       g_i2c_client = client;
+
+#ifdef EMDOOR_DEBUG_GC2145
+       gc2145_client = client;
+       err = sysfs_create_group(&client->dev.kobj, &gc2145_group);
+#endif
+
+       return 0;
+}
+
+static int gc2145_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct gc2145_device *t = to_dev(sd);
+
+       video_unregister_device(t->vdev);
+       v4l2_device_unregister_subdev(sd);
+#ifdef CONFIG_HAS_WAKELOCK
+       wake_lock_destroy(&(t->wake_lock));
+#endif
+       aml_cam_info_unreg(&t->cam_info);
+       kfree(t);
+       return 0;
+}
+
+
+static const struct i2c_device_id gc2145_id[] = {
+       { "gc2145", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, gc2145_id);
+
+static struct i2c_driver gc2145_i2c_driver = {
+       .driver = {
+               .name = "gc2145",
+       },
+       .probe = gc2145_probe,
+       .remove = gc2145_remove,
+       .id_table = gc2145_id,
+};
+
+module_i2c_driver(gc2145_i2c_driver);
+
index 455b512..56ab75d 100644 (file)
@@ -521,9 +521,6 @@ static void canvas_pool_config(void)
        canvas_pool_register_const_canvas(0x70, 0x77, "ppmgr");
        canvas_pool_register_const_canvas(0xe4, 0xef, "encoder");
        canvas_pool_register_const_canvas(0x40, 0x48, "osd");
-#ifdef CONFIG_AMLOGIC_VIDEOIN_MANAGER
-       canvas_pool_register_const_canvas(0x4e, 0x5f, "vm");
-#endif
        canvas_pool_register_const_canvas(0xc0, 0xd7, "amlvideo2");
        /*please add static canvas later. */
 }
index eaea913..a64c180 100644 (file)
@@ -368,17 +368,6 @@ static void vfm_init(void)
 #ifdef CONFIG_TVIN_VIUIN
        char def_ext_id[] = "default_ext";
        char def_ext_name_chain[] = "vdin amvideo2";
-#else /**/
-#ifdef CONFIG_AMLOGIC_VIDEOIN_MANAGER
-       char def_ext_id0[] = "default_ext0";
-       char def_ext_id1[] = "default_ext1";
-#ifdef CONFIG_AMLOGIC_VM_DISABLE_VIDEOLAYER
-       char def_ext_name_chain0[] = "vdin0 vm0";
-       char def_ext_name_chain1[] = "vdin1 vm1";
-#else /**/
-       char def_ext_name_chain[] = "vdin0 vm amvideo";
-#endif /**/
-#endif /**/
 #endif /**/
 #ifdef CONFIG_VDIN_MIPI
        char def_mipi_id[] = "default_mipi";
@@ -417,10 +406,7 @@ static void vfm_init(void)
 #ifdef CONFIG_VDIN_MIPI
        vfm_map_add(def_mipi_id, def_mipi_name_chain);
 #endif /**/
-#ifdef CONFIG_AMLOGIC_VIDEOIN_MANAGER
-       vfm_map_add(def_ext_id0, def_ext_name_chain0);
-       vfm_map_add(def_ext_id1, def_ext_name_chain1);
-#endif /**/
+
 #if (defined CONFIG_TVIN_AFE) || (defined CONFIG_TVIN_HDMI)
        vfm_map_add(tvpath_id, tvpath_chain);
 #endif /**/
diff --git a/include/linux/amlogic/media/camera/aml_cam_info.h b/include/linux/amlogic/media/camera/aml_cam_info.h
new file mode 100644 (file)
index 0000000..b669ef4
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * include/linux/amlogic/media/camera/aml_cam_info.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 __AML_CAM_DEV__
+#define __AML_CAM_DEV__
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/amlogic/i2c-amlogic.h>
+#include <linux/amlogic/media/frame_provider/tvin/tvin_v4l2.h>
+#include <linux/amlogic/media/frame_provider/tvin/tvin.h>
+#include <linux/amlogic/media/camera/flashlight.h>
+
+#define FRONT_CAM      0
+#define BACK_CAM       1
+
+enum resolution_size {
+       SIZE_NULL = 0, SIZE_176X144,    /* 4:3 */
+       SIZE_320X240,   /* 4:3 */
+       SIZE_352X288,   /* 4:3 */
+       SIZE_640X480,   /* 0.3M 4:3 */
+       SIZE_720X405,   /* 0.3M 16:9 */
+       SIZE_800X600,   /* 0.5M 4:3 */
+       SIZE_960X540,   /* 0.5M 16:9 */
+       SIZE_1024X576,  /* 0.6M 16:9 */
+       SIZE_960X720,   /* 0.7M 4:3 */
+       SIZE_1024X768,  /* 0.8M 4:3 */
+       SIZE_1280X720,  /* 0.9M 16:9 */
+       SIZE_1152X864,  /* 1M   4:3 */
+       SIZE_1366X768,  /* 1M   16:9 */
+       SIZE_1280X960,  /* 1.2M 4:3 */
+       SIZE_1280X1024, /* 1.3M 16:9. */
+       SIZE_1400X1050, /* 1.5M 4:3 */
+       SIZE_1600X900,  /* 1.5M 16:9 */
+       SIZE_1600X1200, /* 2M   4:3 */
+       SIZE_1920X1080, /* 2M   16:9 */
+       SIZE_1792X1344, /* 2.4M 4:3 */
+       SIZE_2048X1152, /* 2.4M 16:9 */
+       SIZE_2048X1536, /* 3.2M 4:3 */
+       SIZE_2304X1728, /* 4M   4:3 */
+       SIZE_2560X1440, /* 4M   16:9 */
+       SIZE_2592X1944, /* 5M   4:3 */
+       SIZE_3072X1728, /* 5M   16:9 */
+       SIZE_2816X2112, /* 6M   4:3 */
+       SIZE_3264X1836, /* 6m    16:9 */
+       SIZE_3072X2304, /* 7M   4:3 */
+       SIZE_3200X2400, /* 7.5M 4:3 */
+       SIZE_3264X2448, /* 8M   4:3 */
+       SIZE_3840X2160, /* 8M   16:9 */
+       SIZE_3456X2592, /* 9M   4:3 */
+       SIZE_3600X2700, /* 9.5M 4:3 */
+       SIZE_4096X2304, /* 9.5M 16:9 */
+       SIZE_3672X2754, /* 10M  4:3 */
+       SIZE_3840X2880, /* 11M  4:3 */
+       SIZE_4000X3000, /* 12M  4:3 */
+       SIZE_4608X2592, /* 12M  16:9 */
+       SIZE_4096X3072, /* 12.5M        4:3 */
+       SIZE_4800X3200, /* 15M  4:3 */
+       SIZE_5120X2880, /* 15M  16:9 */
+       SIZE_5120X3840, /* 20M  4:3 */
+       SIZE_6400X4800, /* 30M  4:3 */
+};
+
+typedef int (*aml_cam_probe_fun_t)(struct i2c_adapter *);
+
+struct aml_cam_info_s {
+       struct list_head info_entry;
+       const char *name;
+       unsigned int i2c_bus_num;
+       unsigned int pwdn_act;
+       unsigned int front_back; /* front is 0, back is 1 */
+       unsigned int m_flip;
+       unsigned int v_flip;
+       unsigned int flash;
+       unsigned int auto_focus;
+       unsigned int i2c_addr;
+       const char *motor_driver;
+       const char *resolution;
+       const char *version;
+       unsigned int mclk;
+       unsigned int flash_support;
+       unsigned int flash_ctrl_level;
+       unsigned int torch_support;
+       unsigned int torch_ctrl_level;
+       unsigned int vcm_mode;
+       unsigned int spread_spectrum;
+       unsigned int vdin_path;
+       unsigned int bt_path_count;
+       enum bt_path_e bt_path;
+       enum cam_interface_e interface;
+       enum clk_channel_e clk_channel;
+       /* gpio_t pwdn_pin; */
+       /* gpio_t rst_pin; */
+       /* gpio_t flash_ctrl_pin; */
+       /* gpio_t torch_ctrl_pin; */
+       unsigned int pwdn_pin;
+       unsigned int rst_pin;
+       unsigned int flash_ctrl_pin;
+       unsigned int torch_ctrl_pin;
+       enum resolution_size max_cap_size;
+       enum tvin_color_fmt_e bayer_fmt;
+       const char *config;
+       struct pinctrl *camera_pin_ctrl;
+};
+/* aml_cam_info_t */
+
+struct aml_camera_i2c_fig_s {
+       unsigned short addr;
+       unsigned char val;
+};
+
+struct aml_camera_i2c_fig0_s {
+       unsigned short addr;
+       unsigned short val;
+};
+
+struct aml_camera_i2c_fig1_s {
+       unsigned char addr;
+       unsigned char val;
+};
+
+extern void aml_cam_init(struct aml_cam_info_s *cam_dev);
+extern void aml_cam_uninit(struct aml_cam_info_s *cam_dev);
+extern void aml_cam_flash(struct aml_cam_info_s *cam_dev, int is_on);
+extern void aml_cam_torch(struct aml_cam_info_s *cam_dev, int is_on);
+extern int aml_cam_info_reg(struct aml_cam_info_s *cam_info);
+extern int aml_cam_info_unreg(struct aml_cam_info_s *cam_info);
+
+#endif /* __AML_CAM_DEV__ */
diff --git a/include/linux/amlogic/media/camera/flashlight.h b/include/linux/amlogic/media/camera/flashlight.h
new file mode 100644 (file)
index 0000000..d594372
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * include/linux/amlogic/media/camera/flashlight.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 _VIDEO_AMLOGIC_FLASHLIGHT_INCLUDE_
+#define _VIDEO_AMLOGIC_FLASHLIGHT_INCLUDE_
+struct aml_plat_flashlight_data_s {
+       void (*flashlight_on)(void);
+       void (*flashlight_off)(void);
+};
+
+enum aml_plat_flashlight_status_s {
+       FLASHLIGHT_AUTO = 0,
+       FLASHLIGHT_ON,
+       FLASHLIGHT_OFF,
+       FLASHLIGHT_TORCH,
+       FLASHLIGHT_RED_EYE,
+};
+
+#endif
+
diff --git a/include/linux/amlogic/media/camera/vmapi.h b/include/linux/amlogic/media/camera/vmapi.h
new file mode 100644 (file)
index 0000000..b1d832e
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * include/linux/amlogic/media/camera/vmapi.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 VM_API_INCLUDE_
+#define VM_API_INCLUDE_
+
+struct vm_output_para {
+       int width;
+       int height;
+       int bytesperline;
+       int v4l2_format;
+       int index;
+       int v4l2_memory;
+       int zoom;     /* set -1 as invalid */
+       int mirror;   /* set -1 as invalid */
+       int angle;
+       uintptr_t vaddr;/*unsigned*/
+       unsigned int ext_canvas;
+};
+/*struct vm_output_para*/
+struct videobuf_buffer;
+struct vb2_buffer;
+
+struct vm_init_s {
+       size_t vm_buf_size;
+       struct page *vm_pages;
+       resource_size_t buffer_start;
+       unsigned int vdin_id;
+       unsigned int bt_path_count;
+       bool isused;
+       bool mem_alloc_succeed;
+};
+/*struct vm_init_s*/
+
+int vm_fill_this_buffer(struct videobuf_buffer *vb, struct vm_output_para *para,
+                       struct vm_init_s *info);
+int vm_fill_buffer(struct videobuf_buffer *vb, struct vm_output_para *para);
+
+int vm_fill_buffer2(struct vb2_buffer *vb, struct vm_output_para *para);
+
+#ifdef CONFIG_CMA
+int vm_init_buf(size_t size);
+int vm_init_resource(size_t size, struct vm_init_s *info);
+void vm_deinit_buf(void);
+void vm_deinit_resource(struct vm_init_s *info);
+void vm_reserve_cma(void);
+#endif
+
+#endif /* VM_API_INCLUDE_ */