From a62874b1ea215f91463dc29375a6cc3cfd341c01 Mon Sep 17 00:00:00 2001 From: Guosong Zhou Date: Wed, 2 Jan 2019 06:00:30 -0500 Subject: [PATCH] camera: add dvp camera [1/1] 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 --- MAINTAINERS | 13 + arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts | 87 + arch/arm/configs/meson64_a32_defconfig | 3 + arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts | 87 + arch/arm64/configs/meson64_defconfig | 3 + drivers/amlogic/media/Kconfig | 1 + drivers/amlogic/media/Makefile | 1 + drivers/amlogic/media/camera/Kconfig | 559 ++++ drivers/amlogic/media/camera/Makefile | 15 + drivers/amlogic/media/camera/common/cam_prober.c | 1792 ++++++++++ .../amlogic/media/camera/common/config_parser.c | 1822 +++++++++++ .../amlogic/media/camera/common/config_parser.h | 301 ++ drivers/amlogic/media/camera/common/flashlight.c | 249 ++ drivers/amlogic/media/camera/common/plat_ctrl.c | 208 ++ drivers/amlogic/media/camera/common/plat_ctrl.h | 47 + drivers/amlogic/media/camera/common/vm.c | 2309 +++++++++++++ drivers/amlogic/media/camera/common/vm.h | 139 + drivers/amlogic/media/camera/common/vm_log.h | 44 + drivers/amlogic/media/camera/common/vmcls.h | 189 ++ drivers/amlogic/media/camera/gc2145.c | 3453 ++++++++++++++++++++ drivers/amlogic/media/common/canvas/canvas_mgr.c | 3 - drivers/amlogic/media/common/vfm/vfm.c | 16 +- include/linux/amlogic/media/camera/aml_cam_info.h | 142 + include/linux/amlogic/media/camera/flashlight.h | 34 + include/linux/amlogic/media/camera/vmapi.h | 63 + 25 files changed, 11562 insertions(+), 18 deletions(-) create mode 100644 drivers/amlogic/media/camera/Kconfig create mode 100644 drivers/amlogic/media/camera/Makefile create mode 100644 drivers/amlogic/media/camera/common/cam_prober.c create mode 100644 drivers/amlogic/media/camera/common/config_parser.c create mode 100644 drivers/amlogic/media/camera/common/config_parser.h create mode 100644 drivers/amlogic/media/camera/common/flashlight.c create mode 100644 drivers/amlogic/media/camera/common/plat_ctrl.c create mode 100644 drivers/amlogic/media/camera/common/plat_ctrl.h create mode 100644 drivers/amlogic/media/camera/common/vm.c create mode 100644 drivers/amlogic/media/camera/common/vm.h create mode 100644 drivers/amlogic/media/camera/common/vm_log.h create mode 100644 drivers/amlogic/media/camera/common/vmcls.h create mode 100644 drivers/amlogic/media/camera/gc2145.c create mode 100644 include/linux/amlogic/media/camera/aml_cam_info.h create mode 100644 include/linux/amlogic/media/camera/flashlight.h create mode 100644 include/linux/amlogic/media/camera/vmapi.h diff --git a/MAINTAINERS b/MAINTAINERS index 4ccdbfe..bc4e9eb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14750,3 +14750,16 @@ AMLOGIC MESONAXG RSR DTS M: Yeping Miao 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 +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 diff --git a/arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts b/arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts index 14efeb2..8cf27c5 100644 --- a/arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts +++ b/arch/arm/boot/dts/amlogic/g12a_s905d2_u200.dts @@ -151,6 +151,12 @@ size = <0x04000000>; alignment = <0x400000>; }; + vm0_cma_reserved:linux,vm0_cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x2000000>; + alignment = <0x0 0x400000>; + }; }; gpioleds { @@ -284,6 +290,54 @@ 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"; @@ -789,6 +843,13 @@ }; }; +&i2c2 { + status = "disabled"; + pinctrl-names="default"; + pinctrl-0=<&i2c2_master_pins2>; + clock-frequency = <100000>; +}; + &i2c3 { status = "okay"; pinctrl-names="default"; @@ -1124,6 +1185,32 @@ }; }; + 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 { diff --git a/arch/arm/configs/meson64_a32_defconfig b/arch/arm/configs/meson64_a32_defconfig index 71f5e9f..9cb58f8 100644 --- a/arch/arm/configs/meson64_a32_defconfig +++ b/arch/arm/configs/meson64_a32_defconfig @@ -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 diff --git a/arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts b/arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts index 4ece6da..1a8d55d 100644 --- a/arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts +++ b/arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts @@ -149,6 +149,12 @@ size = <0x0 0x04000000>; alignment = <0x0 0x400000>; }; + vm0_cma_reserved:linux,vm0_cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x2000000>; + alignment = <0x0 0x400000>; + }; }; gpioleds { @@ -282,6 +288,54 @@ 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"; @@ -787,6 +841,13 @@ }; }; +&i2c2 { + status = "disabled"; + pinctrl-names="default"; + pinctrl-0=<&i2c2_master_pins2>; + clock-frequency = <100000>; +}; + &i2c3 { status = "okay"; pinctrl-names="default"; @@ -1122,6 +1183,32 @@ }; }; + 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 { diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 45a3aba..7971d54 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -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 diff --git a/drivers/amlogic/media/Kconfig b/drivers/amlogic/media/Kconfig index bc31627..ded82c0 100644 --- a/drivers/amlogic/media/Kconfig +++ b/drivers/amlogic/media/Kconfig @@ -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 diff --git a/drivers/amlogic/media/Makefile b/drivers/amlogic/media/Makefile index dfb7316..12f643b 100644 --- a/drivers/amlogic/media/Makefile +++ b/drivers/amlogic/media/Makefile @@ -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 index 0000000..41d08be --- /dev/null +++ b/drivers/amlogic/media/camera/Kconfig @@ -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 index 0000000..04fb18c --- /dev/null +++ b/drivers/amlogic/media/camera/Makefile @@ -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 index 0000000..98fe531 --- /dev/null +++ b/drivers/amlogic/media/camera/common/cam_prober.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..9ee62e7 --- /dev/null +++ b/drivers/amlogic/media/camera/common/config_parser.c @@ -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 +#include +#include +#include + +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 index 0000000..c5e7802 --- /dev/null +++ b/drivers/amlogic/media/camera/common/config_parser.h @@ -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 +#include +#include +#include +#include +#include + +#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 index 0000000..51018d9 --- /dev/null +++ b/drivers/amlogic/media/camera/common/flashlight.c @@ -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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 index 0000000..44aa8bd --- /dev/null +++ b/drivers/amlogic/media/camera/common/plat_ctrl.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 index 0000000..6bcb6cb --- /dev/null +++ b/drivers/amlogic/media/camera/common/plat_ctrl.h @@ -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 index 0000000..c994df2 --- /dev/null +++ b/drivers/amlogic/media/camera/common/vm.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vm_log.h" +#include "vm.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/*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, ¶m); + 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 "); diff --git a/drivers/amlogic/media/camera/common/vm.h b/drivers/amlogic/media/camera/common/vm.h new file mode 100644 index 0000000..50305fcd --- /dev/null +++ b/drivers/amlogic/media/camera/common/vm.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/************************************* + ** + ** 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 index 0000000..4733cad --- /dev/null +++ b/drivers/amlogic/media/camera/common/vm_log.h @@ -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 index 0000000..3e81c37 --- /dev/null +++ b/drivers/amlogic/media/camera/common/vmcls.h @@ -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 index 0000000..3150faf --- /dev/null +++ b/drivers/amlogic/media/camera/gc2145.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_HAS_WAKELOCK +#include +#endif +#include +#include +#include +#include +#include +#include "common/plat_ctrl.h" +#include +#include +#include +#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, ¶, &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(¶, 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, ¶); + 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); + diff --git a/drivers/amlogic/media/common/canvas/canvas_mgr.c b/drivers/amlogic/media/common/canvas/canvas_mgr.c index 455b512..56ab75dd 100644 --- a/drivers/amlogic/media/common/canvas/canvas_mgr.c +++ b/drivers/amlogic/media/common/canvas/canvas_mgr.c @@ -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. */ } diff --git a/drivers/amlogic/media/common/vfm/vfm.c b/drivers/amlogic/media/common/vfm/vfm.c index eaea913..a64c180 100644 --- a/drivers/amlogic/media/common/vfm/vfm.c +++ b/drivers/amlogic/media/common/vfm/vfm.c @@ -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 index 0000000..b669ef4 --- /dev/null +++ b/include/linux/amlogic/media/camera/aml_cam_info.h @@ -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 +#include +#include +#include +#include +#include + +#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 index 0000000..d594372 --- /dev/null +++ b/include/linux/amlogic/media/camera/flashlight.h @@ -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 index 0000000..b1d832e --- /dev/null +++ b/include/linux/amlogic/media/camera/vmapi.h @@ -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_ */ -- 2.7.4