v4l2: add mipi pipeline suppport and ov13850 sensor
authorchanghuang.liang <1003615911@qq.com>
Wed, 12 Jan 2022 06:27:34 +0000 (14:27 +0800)
committerchanghuang.liang <1003615911@qq.com>
Wed, 12 Jan 2022 06:27:34 +0000 (14:27 +0800)
arch/riscv/boot/dts/starfive/starfive_jh7110.dts
drivers/media/platform/starfive/Kconfig
drivers/media/platform/starfive/Makefile
drivers/media/platform/starfive/v4l2_driver/ov13850_mipi.c [new file with mode: 0755]
drivers/media/platform/starfive/v4l2_driver/stf_csi_hw_ops.c
drivers/media/platform/starfive/v4l2_driver/stf_csiphy_hw_ops.c
drivers/media/platform/starfive/v4l2_driver/stf_isp_hw_ops.c
drivers/media/platform/starfive/v4l2_driver/stf_vin_hw_ops.c
include/video/stf-vin.h

index 1a9b0cc..edab496 100755 (executable)
                        ngpios = <64>;
                        status = "okay";
                };
-               
+
                trng: trng@1600C000 {
                        compatible = "starfive,trng";
                        reg = <0x0 0x1600C000 0x0 0x4000>;
                        clocks = <&apb12clk>;
                        status = "okay";
                };
-               
+
 
                i2c6: i2c@12060000 {
                        #address-cells = <1>;
                        auto_calc_scl_lhcnt;
 
                        status = "okay";
-                       
-                       
-                       
+
                        sc2235@30 {
                                compatible = "sc2235";
                                reg = <0x30>;
                                        };
                                };
                        };
+
+                       ov13850@10 {
+                compatible = "ovti,ov13850";
+                reg = <0x10>;
+                clocks = <&clk_ext_camera>;
+                clock-names = "xclk";
+                powerdown-gpio = <&gpio 15 0>;
+                reset-gpio = <&gpio 16 0>;
+                //DOVDD-supply = <&v2v8>;
+                rotation = <0>;
+
+                port {
+                    /* CSI2 bus endpoint */
+                    ov13850_to_csi2rx0: endpoint {
+                        remote-endpoint = <&csi2rx0_from_ov13850>;
+                        bus-type = <4>;      /* MIPI CSI-2 D-PHY */
+                        clock-lanes = <2>;
+                        data-lanes = <0 1>;
+                    };
+                };
+            };
                };
                i2c0: i2c@10030000 {
                        #address-cells = <1>;
                        i2c-scl-falling-time-ns = <3000>;
                        auto_calc_scl_lhcnt;
                        status = "okay";
-                       
+
                        ac108_a: ac108@3b {
                                compatible = "x-power,ac108_0";
                                reg = <0x3b>;
                                #sound-dai-cells = <0>;
                                data-protocol = <0>;
                        };
-                       
+
                        wm8960: codec@1a {
                                compatible = "wlf,wm8960";
                                reg = <0x1a>;
                        interrupts = <92 87 86>;
                        // memory-region = <&vin_reserved>;
 
-                       ports { 
+                       ports {
                                port@3 {
                                        reg = <2>; //dvp sensor
 
                                                status = "okay";
                                        };
                                };
+
+                port@4 {
+                                       reg = <3>; //csi2rx0 sensor
+
+                                       /* Parallel bus endpoint */
+                                       csi2rx0_from_ov13850: endpoint {
+                                               remote-endpoint = <&ov13850_to_csi2rx0>;
+                                               bus-type = <4>;      /* MIPI CSI-2 D-PHY */
+                                               clock-lanes = <2>;
+                                               data-lanes = <0 1>;
+                                               status = "okay";
+                                       };
+                               };
                        };
                };
                jpu: jpu@11900000 {
                        clocks = <&canclk>;
                        clock-names = "ipms_can_clk";
                };
-               
+
                ipmscan1: can@130c0000  {
                        compatible = "ipms,canfd";
                        reg = <0x0 0x130c0000 0x0 0x1000>;
                        clocks = <&canclk>;
                        clock-names = "ipms_can_clk";
                };
-               
+
                tdm: tdm@10090000  {
                        compatible = "starfive,tdm";
                        reg = <0x0 0x10090000 0x0 0x1000>;
                        clocks = <&audioclk>;
                        clock-names = "audioclk";
                        dmas = <&dma 20 1>, <&dma 21 1>;
-                       dma-names = "rx","tx";  
+                       dma-names = "rx","tx";
                        #sound-dai-cells = <0>;
                };
-               
+
                spdif0: spdif0@100a0000 {
                        compatible = "starfive,sf-spdif";
                        reg = <0x0 0x100a0000 0x0 0x1000>;
                        clock-names = "audioclk";
                        #sound-dai-cells = <0>;
                };
-               
+
                pwmdac: pwmdac@100b0000 {
                        compatible = "sf,pwmdac";
                        reg = <0x0 0x100b0000 0x0 0x1000>;
                        dma-names = "tx";
                        #sound-dai-cells = <0>;
                };
-               
+
                i2stx: i2stx@100c0000  {
                        compatible = "snps,designware-i2stx";
                        reg = <0x0 0x100c0000 0x0 0x1000>;
                        dmas = <&dma 28>;
                        dma-names = "rx";
                };
-               
+
                pdm: pdm@100d0000 {
                        compatible = "starfive,sf-pdm";
                        reg = <0x0 0x100d0000 0x0 0x1000>;
                        clock-names = "audioclk";
                        #sound-dai-cells = <0>;
                };
-               
+
                i2srx_3ch: i2srx-3ch@100e0000 {
                        compatible = "snps,designware-i2srx";
                        reg = <0x0 0x100e0000 0x0 0x1000>;
                        clock-names = "i2sclk";
                        #sound-dai-cells = <0>;
                };
-               
+
                i2stx_4ch1: i2sdac1@120c0000 {
                        compatible = "snps,designware-i2stx-4ch1";
                        reg = <0x0 0x120c0000 0x0 0x1000>;
                        clock-names = "i2sclk";
                        #sound-dai-cells = <0>;
                };
-               
+
                ptc: pwm@120d0000 {
                        compatible = "starfive,pwm0";
                        reg = <0x0 0x120d0000 0x0 0x10000>;
                        #pwm-cells=<3>;
                        sifive,npwm = <8>;
                };
-               
+
                ac108_mclk: ac108_mclk {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
                        clock-frequency = <24576000>;
                };
-               
+
                wm8960_mclk: wm8960_mclk {
                        compatible = "fixed-clock";
                        #clock-cells = <0>;
                spdif_transmitter: spdif_transmitter {
                        compatible = "linux,spdif-dit";
                        #sound-dai-cells = <0>;
-               };      
-               
+               };
+
                spdif_receiver: spdif_receiver {
                        compatible = "linux,spdif-dir";
                        #sound-dai-cells = <0>;
                };
-               
+
                pwmdac_codec: pwmdac-transmitter {
                        compatible = "linux,pwmdac-dit";
                        #sound-dai-cells = <0>;
                };
-               
-               dmic_codec: dmic_codec { 
+
+               dmic_codec: dmic_codec {
                        compatible = "dmic-codec";
                        #sound-dai-cells = <0>;
-               }; 
+               };
 
                spi0:spi0@10060000 {
                        compatible = "arm,pl022", "arm,primecell";
index 09e35ed..57d613a 100755 (executable)
@@ -24,3 +24,11 @@ config VIN_SENSOR_OV4689
        default n
        help
          Say Y here if you want to have support for VIN sensor OV4689
+
+config VIN_SENSOR_OV13850
+       bool "VIN SENSOR support OV13850"
+       depends on VIDEO_STF_VIN
+       select V4L2_FWNODE
+       default n
+       help
+         Say Y here if you want to have support for VIN sensor OV13850
\ No newline at end of file
index e4e2103..d7a886d 100755 (executable)
@@ -11,6 +11,7 @@
 obj-$(CONFIG_VIN_SENSOR_OV5640) += v4l2_driver/ov5640.o
 obj-$(CONFIG_VIN_SENSOR_SC2235) += v4l2_driver/sc2235.o
 obj-$(CONFIG_VIN_SENSOR_OV4689) += v4l2_driver/ov4689_mipi.o
+obj-$(CONFIG_VIN_SENSOR_OV13850) += v4l2_driver/ov13850_mipi.o
 
 obj-$(CONFIG_VIDEO_STF_VIN) +=         v4l2_driver/stfcamss.o \
                                v4l2_driver/stf_event.o \
@@ -24,4 +25,4 @@ obj-$(CONFIG_VIDEO_STF_VIN) +=        v4l2_driver/stfcamss.o \
                                v4l2_driver/stf_csi_hw_ops.o \
                                v4l2_driver/stf_csiphy_hw_ops.o \
                                v4l2_driver/stf_isp_hw_ops.o \
-                               v4l2_driver/stf_dvp_hw_ops.o 
+                               v4l2_driver/stf_dvp_hw_ops.o
diff --git a/drivers/media/platform/starfive/v4l2_driver/ov13850_mipi.c b/drivers/media/platform/starfive/v4l2_driver/ov13850_mipi.c
new file mode 100755 (executable)
index 0000000..5b0fa15
--- /dev/null
@@ -0,0 +1,1923 @@
+// SPDX-License-Identifier: GPL-2.0-or-later\r
+/*\r
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.\r
+ * Copyright (C) 2014-2017 Mentor Graphics Inc.\r
+ * Copyright (C) 2021 StarFive Technology Co., Ltd.\r
+ */\r
+\r
+#include <linux/clk.h>\r
+#include <linux/clk-provider.h>\r
+#include <linux/clkdev.h>\r
+#include <linux/ctype.h>\r
+#include <linux/delay.h>\r
+#include <linux/device.h>\r
+#include <linux/gpio/consumer.h>\r
+#include <linux/i2c.h>\r
+#include <linux/init.h>\r
+#include <linux/module.h>\r
+#include <linux/of_device.h>\r
+#include <linux/regulator/consumer.h>\r
+#include <linux/slab.h>\r
+#include <linux/types.h>\r
+#include <media/v4l2-async.h>\r
+#include <media/v4l2-ctrls.h>\r
+#include <media/v4l2-device.h>\r
+#include <media/v4l2-event.h>\r
+#include <media/v4l2-fwnode.h>\r
+#include <media/v4l2-subdev.h>\r
+#include "stfcamss.h"\r
+\r
+#define OV13850_XCLK_MIN  6000000\r
+#define OV13850_XCLK_MAX 54000000\r
+\r
+#define OV13850_LINK_FREQ_500MHZ         500000000LL\r
+\r
+/**\r
+OV13850 PLL\r
+\r
+PLL1:\r
+\r
+REF_CLK -> /PREDIVP[0] -> /PREDIV[2:0] -> *DIVP[9:8,7:0] -> /DIVM[3:0] -> /DIV_MIPI[1:0]  -> PCLK\r
+(6-64M)     0x030A         0x0300          0x0301,0x302      0x0303        0x0304\r
+                                                                      `-> MIPI_PHY_CLK\r
+\r
+\r
+PLL2:\r
+                           000: 1\r
+                           001: 1.5\r
+                           010: 2\r
+                           011: 2.5\r
+                           100: 3\r
+                           101: 4\r
+            0: /1          110: 6\r
+            1: /2          111: 8\r
+REF_CLK -> /PREDIVP[3] -> /PREDIV[2:0] -> /DIVP[9:0] -> /DIVDAC[3:0] -> DAC_CLK =\r
+(6~64M)    0x3611\r
+                                                     -> /DIVSP[3:0] -> /DIVS[2:0] -> SCLK\r
+\r
+                                                     -> /(1+DIVSRAM[3:0]) -> SRAM_CLK\r
+**/\r
+\r
+// PREDIVP\r
+#define OV13850_REG_PLL1_PREDIVP        0x030a\r
+#define OV13850_PREDIVP_1   0\r
+#define OV13850_PREDIVP_2   1\r
+\r
+// PREDIV\r
+#define OV13850_REG_PLL1_PREDIV         0x0300\r
+#define OV13850_PREDIV_1    0\r
+#define OV13850_PREDIV_1_5  1\r
+#define OV13850_PREDIV_2    2\r
+#define OV13850_PREDIV_2_5  3\r
+#define OV13850_PREDIV_3    4\r
+#define OV13850_PREDIV_4    5\r
+#define OV13850_PREDIV_6    6\r
+#define OV13850_PREDIV_8    7\r
+\r
+// DIVP\r
+#define OV13850_REG_PLL1_DIVP_H         0x0301\r
+#define OV13850_REG_PLL1_DIVP_L         0x0302\r
+#define OV13850_REG_PLL1_DIVP           OV13850_REG_PLL1_DIVP_H\r
+\r
+// DIVM\r
+#define OV13850_REG_PLL1_DIVM           0x0303\r
+#define OV13850_DIVM(n)     ((n)-1) // n=1~16\r
+\r
+// DIV_MIPI\r
+#define OV13850_REG_PLL1_DIV_MIPI       0x0304\r
+#define OV13850_DIV_MIPI_4  0\r
+#define OV13850_DIV_MIPI_5  1\r
+#define OV13850_DIV_MIPI_6  2\r
+#define OV13850_DIV_MIPI_8  3\r
+\r
+// system control\r
+#define OV13850_STREAM_CTRL             0x0100\r
+#define OV13850_REG_MIPI_SC             0x300f\r
+#define OV13850_MIPI_SC_8_BIT           0x0\r
+#define OV13850_MIPI_SC_10_BIT          0x1\r
+#define OV13850_MIPI_SC_12_BIT          0x2\r
+#define OV13850_GET_MIPI_SC_MIPI_BIT(v)         ((v) & 0x3)\r
+#define OV13850_REG_MIPI_SC_CTRL0       0x3012\r
+#define OV13850_GET_MIPI_SC_CTRL0_LANE_NUM(v)   ((v)>>4 & 0xf)\r
+\r
+// timing\r
+#define OV13850_REG_H_CROP_START_H      0x3800\r
+#define OV13850_REG_H_CROP_START_L      0x3801\r
+#define OV13850_REG_H_CROP_START        OV13850_REG_H_CROP_START_H\r
+#define OV13850_REG_V_CROP_START_H      0x3802\r
+#define OV13850_REG_V_CROP_START_L      0x3803\r
+#define OV13850_REG_V_CROP_START        OV13850_REG_V_CROP_START_H\r
+\r
+#define OV13850_REG_H_CROP_END_H        0x3804\r
+#define OV13850_REG_H_CROP_END_L        0x3805\r
+#define OV13850_REG_H_CROP_END          OV13850_REG_H_CROP_END_H\r
+#define OV13850_REG_V_CROP_END_H        0x3806\r
+#define OV13850_REG_V_CROP_END_L        0x3807\r
+#define OV13850_REG_V_CROP_END          OV13850_REG_V_CROP_END_H\r
+\r
+#define OV13850_REG_H_OUTPUT_SIZE_H     0x3808\r
+#define OV13850_REG_H_OUTPUT_SIZE_L     0x3809\r
+#define OV13850_REG_H_OUTPUT_SIZE       OV13850_REG_H_OUTPUT_SIZE_H\r
+#define OV13850_REG_V_OUTPUT_SIZE_H     0x380a\r
+#define OV13850_REG_V_OUTPUT_SIZE_L     0x380b\r
+#define OV13850_REG_V_OUTPUT_SIZE       OV13850_REG_V_OUTPUT_SIZE_H\r
+\r
+#define OV13850_REG_TIMING_HTS_H        0x380c\r
+#define OV13850_REG_TIMING_HTS_L        0x380d\r
+#define OV13850_REG_TIMING_HTS          OV13850_REG_TIMING_HTS_H\r
+#define OV13850_REG_TIMING_VTS_H        0x380e\r
+#define OV13850_REG_TIMING_VTS_L        0x380f\r
+#define OV13850_REG_TIMING_VTS          OV13850_REG_TIMING_VTS_H\r
+\r
+\r
+#define OV13850_REG_H_WIN_OFF_H         0x3810\r
+#define OV13850_REG_H_WIN_OFF_L         0x3811\r
+#define OV13850_REG_V_WIN_OFF_H         0x3812\r
+#define OV13850_REG_V_WIN_OFF_L         0x3813\r
+\r
+#define OV13850_REG_H_INC               0x3814\r
+#define OV13850_REG_V_INC               0x3815\r
+\r
+enum ov13850_mode_id {\r
+       OV13850_MODE_1080P_1920_1080 = 0,\r
+    OV13850_NUM_MODES,\r
+};\r
+\r
+enum ov13850_frame_rate {\r
+       OV13850_15_FPS = 0,\r
+       OV13850_30_FPS,\r
+    OV13850_60_FPS,\r
+       OV13850_NUM_FRAMERATES,\r
+};\r
+\r
+static const int ov13850_framerates[] = {\r
+       [OV13850_15_FPS] = 15,\r
+       [OV13850_30_FPS] = 30,\r
+    [OV13850_60_FPS] = 60,\r
+};\r
+\r
+struct ov13850_pixfmt {\r
+       u32 code;\r
+       u32 colorspace;\r
+};\r
+\r
+static const struct ov13850_pixfmt ov13850_formats[] = {\r
+       { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB, },\r
+       { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_COLORSPACE_SRGB, },\r
+       { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_COLORSPACE_SRGB, },\r
+       { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, },\r
+};\r
+\r
+/* regulator supplies */\r
+static const char * const ov13850_supply_name[] = {\r
+       "DOVDD", /* Digital I/O (1.8V) supply */\r
+       "AVDD",  /* Analog (2.8V) supply */\r
+       "DVDD",  /* Digital Core (1.5V) supply */\r
+};\r
+\r
+#define OV13850_NUM_SUPPLIES ARRAY_SIZE(ov13850_supply_name)\r
+\r
+/*\r
+ * Image size under 1280 * 960 are SUBSAMPLING\r
+ * Image size upper 1280 * 960 are SCALING\r
+ */\r
+enum ov13850_downsize_mode {\r
+       SUBSAMPLING,\r
+       SCALING,\r
+};\r
+\r
+struct reg_value {\r
+       u16 reg_addr;\r
+       u8 val;\r
+       u8 mask;\r
+       u32 delay_ms;\r
+};\r
+\r
+struct ov13850_mode_info {\r
+       enum ov13850_mode_id id;\r
+       enum ov13850_downsize_mode dn_mode;\r
+       u32 hact;\r
+       u32 htot;\r
+       u32 vact;\r
+       u32 vtot;\r
+       const struct reg_value *reg_data;\r
+       u32 reg_data_size;\r
+       u32 max_fps;\r
+};\r
+\r
+struct ov13850_ctrls {\r
+       struct v4l2_ctrl_handler handler;\r
+       struct v4l2_ctrl *pixel_rate;\r
+       struct {\r
+               struct v4l2_ctrl *exposure;\r
+       };\r
+       struct {\r
+               struct v4l2_ctrl *auto_wb;\r
+               struct v4l2_ctrl *blue_balance;\r
+               struct v4l2_ctrl *red_balance;\r
+       };\r
+       struct {\r
+               struct v4l2_ctrl *anal_gain;\r
+       };\r
+       struct v4l2_ctrl *brightness;\r
+       struct v4l2_ctrl *light_freq;\r
+       struct v4l2_ctrl *link_freq;\r
+       struct v4l2_ctrl *saturation;\r
+       struct v4l2_ctrl *contrast;\r
+       struct v4l2_ctrl *hue;\r
+       struct v4l2_ctrl *test_pattern;\r
+       struct v4l2_ctrl *hflip;\r
+       struct v4l2_ctrl *vflip;\r
+};\r
+\r
+struct ov13850_dev {\r
+       struct i2c_client *i2c_client;\r
+       struct v4l2_subdev sd;\r
+       struct media_pad pad;\r
+       struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */\r
+       struct clk *xclk; /* system clock to OV13850 */\r
+       u32 xclk_freq;\r
+\r
+       struct regulator_bulk_data supplies[OV13850_NUM_SUPPLIES];\r
+       struct gpio_desc *reset_gpio;\r
+       struct gpio_desc *pwdn_gpio;\r
+       bool   upside_down;\r
+\r
+       /* lock to protect all members below */\r
+       struct mutex lock;\r
+\r
+       int power_count;\r
+\r
+       struct v4l2_mbus_framefmt fmt;\r
+    bool pending_fmt_change;\r
+\r
+       const struct ov13850_mode_info *current_mode;\r
+       const struct ov13850_mode_info *last_mode;\r
+       enum ov13850_frame_rate current_fr;\r
+       struct v4l2_fract frame_interval;\r
+\r
+       struct ov13850_ctrls ctrls;\r
+\r
+       u32 prev_sysclk, prev_hts;\r
+       u32 ae_low, ae_high, ae_target;\r
+\r
+       bool pending_mode_change;\r
+       bool streaming;\r
+};\r
+\r
+static inline struct ov13850_dev *to_ov13850_dev(struct v4l2_subdev *sd)\r
+{\r
+       return container_of(sd, struct ov13850_dev, sd);\r
+}\r
+\r
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)\r
+{\r
+       return &container_of(ctrl->handler, struct ov13850_dev,\r
+                       ctrls.handler)->sd;\r
+}\r
+\r
+/* ov13850 initial register */\r
+static const struct reg_value ov13850_init_setting_30fps_1080P[] = {\r
+\r
+};\r
+\r
+static const struct reg_value ov13850_setting_1080P_1920_1080[] = {\r
+//;XVCLK=24Mhz, SCLK=4x120Mhz, MIPI 640Mbps, DACCLK=240Mhz\r
+/*\r
+* using quarter size to scale down\r
+*/\r
+    {0x0103, 0x01, 0, 0}, // ; software reset\r
+\r
+    {0x0300, 0x01, 0, 0}, //; PLL\r
+    {0x0301, 0x00, 0, 0}, //; PLL1_DIVP_hi\r
+    {0x0302, 0x28, 0, 0}, //; PLL1_DIVP_lo\r
+    {0x0303, 0x00, 0, 0}, // ; PLL\r
+    {0x030a, 0x00, 0, 0}, // ; PLL\r
+    //{0xffff, 20, 0, 0},\r
+    {0x300f, 0x11, 0, 0}, // SFC modified, MIPI_SRC, [1:0] 00-8bit, 01-10bit, 10-12bit\r
+    {0x3010, 0x01, 0, 0}, // ; MIPI PHY\r
+    {0x3011, 0x76, 0, 0}, // ; MIPI PHY\r
+    {0x3012, 0x41, 0, 0}, // ; MIPI 4 lane\r
+    {0x3013, 0x12, 0, 0}, // ; MIPI control\r
+    {0x3014, 0x11, 0, 0}, // ; MIPI control\r
+    {0x301f, 0x03, 0, 0}, //\r
+    {0x3106, 0x00, 0, 0}, //\r
+    {0x3210, 0x47, 0, 0}, //\r
+    {0x3500, 0x00, 0, 0}, // ; exposure HH\r
+    {0x3501, 0x67, 0, 0}, // ; exposure H\r
+    {0x3502, 0x80, 0, 0}, // ; exposure L\r
+    {0x3506, 0x00, 0, 0}, // ; short exposure HH\r
+    {0x3507, 0x02, 0, 0}, // ; short exposure H\r
+    {0x3508, 0x00, 0, 0}, // ; shour exposure L\r
+    {0x3509, 0x10, 0, 0},//00},//8},\r
+    {0x350a, 0x00, 0, 0}, // ; gain H\r
+    {0x350b, 0x10, 0, 0}, // ; gain L\r
+    {0x350e, 0x00, 0, 0}, // ; short gain H\r
+    {0x350f, 0x10, 0, 0}, // ; short gain L\r
+    {0x3600, 0x40, 0, 0}, // ; analog control\r
+    {0x3601, 0xfc, 0, 0}, // ; analog control\r
+    {0x3602, 0x02, 0, 0}, // ; analog control\r
+    {0x3603, 0x48, 0, 0}, // ; analog control\r
+    {0x3604, 0xa5, 0, 0}, // ; analog control\r
+    {0x3605, 0x9f, 0, 0}, // ; analog control\r
+    {0x3607, 0x00, 0, 0}, // ; analog control\r
+    {0x360a, 0x40, 0, 0}, // ; analog control\r
+    {0x360b, 0x91, 0, 0}, // ; analog control\r
+    {0x360c, 0x49, 0, 0}, // ; analog control\r
+    {0x360f, 0x8a, 0, 0}, //\r
+    {0x3611, 0x10, 0, 0}, // ; PLL2\r
+    //{0x3612, 0x23, 0, 0}, // ; PLL2\r
+    {0x3612, 0x13, 0, 0}, // ; PLL2\r
+    //{0x3613, 0x33, 0, 0}, // ; PLL2\r
+    {0x3613, 0x22, 0, 0}, // ; PLL2\r
+    //{0xffff, 50, 0, 0},\r
+    {0x3614, 0x28, 0, 0}, //[7:0] PLL2_DIVP lo\r
+    {0x3615, 0x08, 0, 0}, //[7:6] Debug mode, [5:4] N_pump clock div, [3:2] P_pump clock div, [1:0] PLL2_DIVP hi\r
+    {0x3641, 0x02, 0, 0},\r
+    {0x3660, 0x82, 0, 0},\r
+    {0x3668, 0x54, 0, 0},\r
+    {0x3669, 0x40, 0, 0},\r
+    {0x3667, 0xa0, 0, 0},\r
+    {0x3702, 0x40, 0, 0},\r
+    {0x3703, 0x44, 0, 0},\r
+    {0x3704, 0x2c, 0, 0},\r
+    {0x3705, 0x24, 0, 0},\r
+    {0x3706, 0x50, 0, 0},\r
+    {0x3707, 0x44, 0, 0},\r
+    {0x3708, 0x3c, 0, 0},\r
+    {0x3709, 0x1f, 0, 0},\r
+    {0x370a, 0x26, 0, 0},\r
+    {0x370b, 0x3c, 0, 0},\r
+    {0x3720, 0x66, 0, 0},\r
+    {0x3722, 0x84, 0, 0},\r
+    {0x3728, 0x40, 0, 0},\r
+    {0x372a, 0x00, 0, 0},\r
+    {0x372f, 0x90, 0, 0},\r
+    {0x3710, 0x28, 0, 0},\r
+    {0x3716, 0x03, 0, 0},\r
+    {0x3718, 0x10, 0, 0},\r
+    {0x3719, 0x08, 0, 0},\r
+    {0x371c, 0xfc, 0, 0},\r
+    {0x3760, 0x13, 0, 0},\r
+    {0x3761, 0x34, 0, 0},\r
+    {0x3767, 0x24, 0, 0},\r
+    {0x3768, 0x06, 0, 0},\r
+    {0x3769, 0x45, 0, 0},\r
+    {0x376c, 0x23, 0, 0},\r
+    {0x3d84, 0x00, 0, 0}, // ; OTP program disable\r
+    {0x3d85, 0x17, 0, 0}, // ; OTP power up load data enable, power load setting enable, software load setting\r
+    {0x3d8c, 0x73, 0, 0}, // ; OTP start address H\r
+    {0x3d8d, 0xbf, 0, 0}, // ; OTP start address L\r
+    {0x3800, 0x00, 0, 0}, // ; H crop start H\r
+    {0x3801, 0x08, 0, 0}, // ; H crop start L\r
+    {0x3802, 0x00, 0, 0}, // ; V crop start H\r
+    {0x3803, 0x04, 0, 0}, // ; V crop start L\r
+    {0x3804, 0x10, 0, 0}, // ; H crop end H\r
+    {0x3805, 0x97, 0, 0}, // ; H crop end L\r
+    {0x3806, 0x0c, 0, 0}, // ; V crop end H\r
+    {0x3807, 0x4b, 0, 0}, // ; V crop end L\r
+    {0x3808, 0x08, 0, 0}, // ; H output size H\r
+    {0x3809, 0x40, 0, 0}, // ; H output size L\r
+    {0x380a, 0x06, 0, 0}, // ; V output size H\r
+    {0x380b, 0x20, 0, 0}, // ; V output size L\r
+    {0x380c, 0x25, 0, 0}, // ; HTS H\r
+    {0x380d, 0x80, 0, 0}, // ; HTS L\r
+    {0x380e, 0x06, 0, 0}, // ; VTS H\r
+    {0x380f, 0x80, 0, 0}, // ; VTS L\r
+    {0x3810, 0x00, 0, 0}, // ; H win off H\r
+    {0x3811, 0x04, 0, 0}, // ; H win off L\r
+    {0x3812, 0x00, 0, 0}, // ; V win off H\r
+    {0x3813, 0x02, 0, 0}, // ; V win off L\r
+    {0x3814, 0x31, 0, 0}, // ; H inc\r
+    {0x3815, 0x31, 0, 0}, // ; V inc\r
+    {0x3820, 0x02, 0, 0}, // ; V flip off, V bin on\r
+    {0x3821, 0x05, 0, 0}, // ; H mirror on, H bin on\r
+    {0x3834, 0x00, 0, 0}, //\r
+    {0x3835, 0x1c, 0, 0}, // ; cut_en, vts_auto, blk_col_dis\r
+    {0x3836, 0x08, 0, 0}, //\r
+    {0x3837, 0x02, 0, 0}, //\r
+    {0x4000, 0xf1, 0, 0},//c1}, // ; BLC offset trig en, format change trig en, gain trig en, exp trig en, median en\r
+    {0x4001, 0x00, 0, 0}, // ; BLC\r
+    {0x400b, 0x0c, 0, 0}, // ; BLC\r
+    {0x4011, 0x00, 0, 0}, // ; BLC\r
+    {0x401a, 0x00, 0, 0}, // ; BLC\r
+    {0x401b, 0x00, 0, 0}, // ; BLC\r
+    {0x401c, 0x00, 0, 0}, // ; BLC\r
+    {0x401d, 0x00, 0, 0}, // ; BLC\r
+    {0x4020, 0x00, 0, 0}, // ; BLC\r
+    {0x4021, 0xe4, 0, 0}, // ; BLC\r
+    {0x4022, 0x07, 0, 0}, // ; BLC\r
+    {0x4023, 0x5f, 0, 0}, // ; BLC\r
+    {0x4024, 0x08, 0, 0}, // ; BLC\r
+    {0x4025, 0x44, 0, 0}, // ; BLC\r
+    {0x4026, 0x08, 0, 0}, // ; BLC\r
+    {0x4027, 0x47, 0, 0}, // ; BLC\r
+    {0x4028, 0x00, 0, 0}, // ; BLC\r
+    {0x4029, 0x02, 0, 0}, // ; BLC\r
+    {0x402a, 0x04, 0, 0}, // ; BLC\r
+    {0x402b, 0x08, 0, 0}, // ; BLC\r
+    {0x402c, 0x02, 0, 0}, // ; BLC\r
+    {0x402d, 0x02, 0, 0}, // ; BLC\r
+    {0x402e, 0x0c, 0, 0}, // ; BLC\r
+    {0x402f, 0x08, 0, 0}, // ; BLC\r
+    {0x403d, 0x2c, 0, 0}, //\r
+    {0x403f, 0x7f, 0, 0}, //\r
+    {0x4500, 0x82, 0, 0}, // ; BLC\r
+    {0x4501, 0x38, 0, 0}, // ; BLC\r
+    {0x4601, 0x04, 0, 0}, //\r
+    {0x4602, 0x22, 0, 0}, //\r
+    {0x4603, 0x01, 0, 0}, //; VFIFO\r
+    {0x4837, 0x19, 0, 0}, //; MIPI global timing\r
+    {0x4d00, 0x04, 0, 0}, // ; temperature monitor\r
+    {0x4d01, 0x42, 0, 0}, //  ; temperature monitor\r
+    {0x4d02, 0xd1, 0, 0}, //  ; temperature monitor\r
+    {0x4d03, 0x90, 0, 0}, //  ; temperature monitor\r
+    {0x4d04, 0x66, 0, 0}, //  ; temperature monitor\r
+    {0x4d05, 0x65, 0, 0}, // ; temperature monitor\r
+    {0x5000, 0x0e, 0, 0}, // ; windowing enable, BPC on, WPC on, Lenc on\r
+    {0x5001, 0x03, 0, 0}, // ; BLC enable, MWB on\r
+    {0x5002, 0x07, 0, 0}, //\r
+    {0x5013, 0x40, 0, 0},\r
+    {0x501c, 0x00, 0, 0},\r
+    {0x501d, 0x10, 0, 0},\r
+    //{0x5057, 0x56, 0, 0},//add\r
+    {0x5056, 0x08, 0, 0},\r
+    {0x5058, 0x08, 0, 0},\r
+    {0x505a, 0x08, 0, 0},\r
+    {0x5242, 0x00, 0, 0},\r
+    {0x5243, 0xb8, 0, 0},\r
+    {0x5244, 0x00, 0, 0},\r
+    {0x5245, 0xf9, 0, 0},\r
+    {0x5246, 0x00, 0, 0},\r
+    {0x5247, 0xf6, 0, 0},\r
+    {0x5248, 0x00, 0, 0},\r
+    {0x5249, 0xa6, 0, 0},\r
+    {0x5300, 0xfc, 0, 0},\r
+    {0x5301, 0xdf, 0, 0},\r
+    {0x5302, 0x3f, 0, 0},\r
+    {0x5303, 0x08, 0, 0},\r
+    {0x5304, 0x0c, 0, 0},\r
+    {0x5305, 0x10, 0, 0},\r
+    {0x5306, 0x20, 0, 0},\r
+    {0x5307, 0x40, 0, 0},\r
+    {0x5308, 0x08, 0, 0},\r
+    {0x5309, 0x08, 0, 0},\r
+    {0x530a, 0x02, 0, 0},\r
+    {0x530b, 0x01, 0, 0},\r
+    {0x530c, 0x01, 0, 0},\r
+    {0x530d, 0x0c, 0, 0},\r
+    {0x530e, 0x02, 0, 0},\r
+    {0x530f, 0x01, 0, 0},\r
+    {0x5310, 0x01, 0, 0},\r
+    {0x5400, 0x00, 0, 0},\r
+    {0x5401, 0x61, 0, 0},\r
+    {0x5402, 0x00, 0, 0},\r
+    {0x5403, 0x00, 0, 0},\r
+    {0x5404, 0x00, 0, 0},\r
+    {0x5405, 0x40, 0, 0},\r
+    {0x540c, 0x05, 0, 0},\r
+    {0x5b00, 0x00, 0, 0},\r
+    {0x5b01, 0x00, 0, 0},\r
+    {0x5b02, 0x01, 0, 0},\r
+    {0x5b03, 0xff, 0, 0},\r
+    {0x5b04, 0x02, 0, 0},\r
+    {0x5b05, 0x6c, 0, 0},\r
+    {0x5b09, 0x02, 0, 0}, //\r
+    //{0x5e00, 0x00, 0, 0}, // ; test pattern disable\r
+    //{0x5e00, 0x80, 0, 0}, // ; test pattern enable\r
+    {0x5e10, 0x1c, 0, 0}, // ; ISP test disable\r
+\r
+    //{0x0300, 0x01, 0, 0},// ; PLL\r
+    //{0x0302, 0x28, 0, 0},// ; PLL\r
+    //{0xffff,  50, 0, 0},\r
+    {0x3501, 0x67, 0, 0},// ; Exposure H\r
+    {0x370a, 0x26, 0, 0},//\r
+    {0x372a, 0x00, 0, 0},\r
+    {0x372f, 0x90, 0, 0},\r
+    {0x3801, 0x08, 0, 0}, //; H crop start L\r
+    {0x3803, 0x04, 0, 0}, //; V crop start L\r
+    {0x3805, 0x97, 0, 0}, //; H crop end L\r
+    {0x3807, 0x4b, 0, 0}, //; V crop end L\r
+    {0x3808, 0x08, 0, 0}, //; H output size H\r
+    {0x3809, 0x40, 0, 0}, //; H output size L\r
+    {0x380a, 0x06, 0, 0}, //; V output size H\r
+    {0x380b, 0x20, 0, 0}, //; V output size L\r
+    {0x380c, 0x25, 0, 0}, //; HTS H\r
+    {0x380d, 0x80, 0, 0}, //; HTS L\r
+    {0x380e, 0x0a, 0, 0},//6}, //; VTS H\r
+    {0x380f, 0x80, 0, 0}, //; VTS L\r
+    {0x3813, 0x02, 0, 0}, //; V win off\r
+    {0x3814, 0x31, 0, 0}, //; H inc\r
+    {0x3815, 0x31, 0, 0}, //; V inc\r
+    {0x3820, 0x02, 0, 0}, //; V flip off, V bin on\r
+    {0x3821, 0x05, 0, 0}, //; H mirror on, H bin on\r
+    {0x3836, 0x08, 0, 0}, //\r
+    {0x3837, 0x02, 0, 0}, //\r
+    {0x4020, 0x00, 0, 0}, //\r
+    {0x4021, 0xe4, 0, 0}, //\r
+    {0x4022, 0x07, 0, 0}, //\r
+    {0x4023, 0x5f, 0, 0}, //\r
+    {0x4024, 0x08, 0, 0}, //\r
+    {0x4025, 0x44, 0, 0}, //\r
+    {0x4026, 0x08, 0, 0}, //\r
+    {0x4027, 0x47, 0, 0}, //\r
+    {0x4603, 0x01, 0, 0}, //; VFIFO\r
+    {0x4837, 0x19, 0, 0}, //; MIPI global timing\r
+    {0x4802, 0x42, 0, 0},  //default 0x00\r
+    {0x481a, 0x00, 0, 0},\r
+    {0x481b, 0x1c, 0, 0},   //default 0x3c  prepare\r
+    {0x4826, 0x12, 0, 0},   //default 0x32  trail\r
+    {0x5401, 0x61, 0, 0}, //\r
+    {0x5405, 0x40, 0, 0}, //\r
+\r
+    //{0xffff, 200, 0, 0},\r
+    //{0xffff, 200, 0, 0},\r
+    //{0xffff, 200, 0, 0},\r
+\r
+    //{0x0100, 0x01, 0, 0}, //; wake up, streaming\r
+};\r
+\r
+/* power-on sensor init reg table */\r
+static const struct ov13850_mode_info ov13850_mode_init_data = {\r
+       OV13850_MODE_1080P_1920_1080, SCALING,\r
+       1920, 0x6e0, 1080, 0x470,\r
+       ov13850_init_setting_30fps_1080P,\r
+       ARRAY_SIZE(ov13850_init_setting_30fps_1080P),\r
+       OV13850_30_FPS,\r
+};\r
+\r
+static const struct ov13850_mode_info\r
+ov13850_mode_data[OV13850_NUM_MODES] = {\r
+       {OV13850_MODE_1080P_1920_1080, SCALING,\r
+        1920, 0x6e0, 1080, 0x470,\r
+        ov13850_setting_1080P_1920_1080,\r
+        ARRAY_SIZE(ov13850_setting_1080P_1920_1080),\r
+        OV13850_30_FPS},\r
+};\r
+\r
+static int ov13850_write_reg(struct ov13850_dev *sensor, u16 reg, u8 val)\r
+{\r
+       struct i2c_client *client = sensor->i2c_client;\r
+       struct i2c_msg msg;\r
+       u8 buf[3];\r
+       int ret;\r
+\r
+       buf[0] = reg >> 8;\r
+       buf[1] = reg & 0xff;\r
+       buf[2] = val;\r
+\r
+       msg.addr = client->addr;\r
+       msg.flags = client->flags;\r
+       msg.buf = buf;\r
+       msg.len = sizeof(buf);\r
+\r
+       ret = i2c_transfer(client->adapter, &msg, 1);\r
+       if (ret < 0) {\r
+               dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",\r
+                       __func__, reg, val);\r
+               return ret;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_read_reg(struct ov13850_dev *sensor, u16 reg, u8 *val)\r
+{\r
+       struct i2c_client *client = sensor->i2c_client;\r
+       struct i2c_msg msg[2];\r
+       u8 buf[2];\r
+       int ret;\r
+\r
+       buf[0] = reg >> 8;\r
+       buf[1] = reg & 0xff;\r
+\r
+       msg[0].addr = client->addr;\r
+       msg[0].flags = client->flags;\r
+       msg[0].buf = buf;\r
+       msg[0].len = sizeof(buf);\r
+\r
+       msg[1].addr = client->addr;\r
+       msg[1].flags = client->flags | I2C_M_RD;\r
+       msg[1].buf = buf;\r
+       msg[1].len = 1;\r
+\r
+       ret = i2c_transfer(client->adapter, msg, 2);\r
+       if (ret < 0) {\r
+               dev_err(&client->dev, "%s: error: reg=%x\n",\r
+                       __func__, reg);\r
+               return ret;\r
+       }\r
+\r
+       *val = buf[0];\r
+       return 0;\r
+}\r
+\r
+static int ov13850_read_reg16(struct ov13850_dev *sensor, u16 reg, u16 *val)\r
+{\r
+       u8 hi, lo;\r
+       int ret;\r
+\r
+       ret = ov13850_read_reg(sensor, reg, &hi);\r
+       if (ret)\r
+               return ret;\r
+       ret = ov13850_read_reg(sensor, reg + 1, &lo);\r
+       if (ret)\r
+               return ret;\r
+\r
+       *val = ((u16)hi << 8) | (u16)lo;\r
+       return 0;\r
+}\r
+\r
+static int ov13850_write_reg16(struct ov13850_dev *sensor, u16 reg, u16 val)\r
+{\r
+       int ret;\r
+\r
+       ret = ov13850_write_reg(sensor, reg, val >> 8);\r
+       if (ret)\r
+               return ret;\r
+\r
+       return ov13850_write_reg(sensor, reg + 1, val & 0xff);\r
+}\r
+\r
+static int ov13850_mod_reg(struct ov13850_dev *sensor, u16 reg,\r
+                       u8 mask, u8 val)\r
+{\r
+       u8 readval;\r
+       int ret;\r
+\r
+       ret = ov13850_read_reg(sensor, reg, &readval);\r
+       if (ret)\r
+               return ret;\r
+\r
+       readval &= ~mask;\r
+       val &= mask;\r
+       val |= readval;\r
+\r
+       return ov13850_write_reg(sensor, reg, val);\r
+}\r
+\r
+static int ov13850_set_timings(struct ov13850_dev *sensor,\r
+                       const struct ov13850_mode_info *mode)\r
+{\r
+       int ret;\r
+\r
+    ret = ov13850_write_reg16(sensor, OV13850_REG_H_OUTPUT_SIZE, mode->hact);\r
+       if (ret < 0)\r
+               return ret;\r
+\r
+       ret = ov13850_write_reg16(sensor, OV13850_REG_V_OUTPUT_SIZE, mode->vact);\r
+       if (ret < 0)\r
+               return ret;\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_load_regs(struct ov13850_dev *sensor,\r
+                       const struct ov13850_mode_info *mode)\r
+{\r
+       const struct reg_value *regs = mode->reg_data;\r
+       unsigned int i;\r
+       u32 delay_ms;\r
+       u16 reg_addr;\r
+       u8 mask, val;\r
+       int ret = 0;\r
+\r
+       st_info(ST_SENSOR, "%s, mode = 0x%x\n", __func__, mode->id);\r
+       for (i = 0; i < mode->reg_data_size; ++i, ++regs) {\r
+               delay_ms = regs->delay_ms;\r
+               reg_addr = regs->reg_addr;\r
+               val = regs->val;\r
+               mask = regs->mask;\r
+\r
+               if (mask)\r
+                       ret = ov13850_mod_reg(sensor, reg_addr, mask, val);\r
+               else\r
+                       ret = ov13850_write_reg(sensor, reg_addr, val);\r
+               if (ret)\r
+                       break;\r
+\r
+               if (delay_ms)\r
+                       usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);\r
+       }\r
+\r
+       return ov13850_set_timings(sensor, mode);\r
+}\r
+\r
+\r
+\r
+static int ov13850_get_gain(struct ov13850_dev *sensor)\r
+{\r
+       u32 gain = 0;\r
+       u8 val;\r
+\r
+       return gain;\r
+}\r
+\r
+static int ov13850_set_gain(struct ov13850_dev *sensor, int gain)\r
+{\r
+       u8 val;\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_stream_mipi(struct ov13850_dev *sensor, bool on)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_get_sysclk(struct ov13850_dev *sensor)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_night_mode(struct ov13850_dev *sensor)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_get_hts(struct ov13850_dev *sensor)\r
+{\r
+       /* read HTS from register settings */\r
+       u16 hts;\r
+       int ret;\r
+\r
+       ret = ov13850_read_reg16(sensor, OV13850_REG_TIMING_HTS, &hts);\r
+       if (ret)\r
+               return ret;\r
+       return hts;\r
+}\r
+\r
+static int ov13850_set_hts(struct ov13850_dev *sensor, int hts)\r
+{\r
+       return ov13850_write_reg16(sensor, OV13850_REG_TIMING_HTS, hts);\r
+}\r
+\r
+\r
+static int ov13850_get_vts(struct ov13850_dev *sensor)\r
+{\r
+       u16 vts;\r
+       int ret;\r
+\r
+       ret = ov13850_read_reg16(sensor, OV13850_REG_TIMING_VTS, &vts);\r
+       if (ret)\r
+               return ret;\r
+       return vts;\r
+}\r
+\r
+static int ov13850_set_vts(struct ov13850_dev *sensor, int vts)\r
+{\r
+       return ov13850_write_reg16(sensor, OV13850_REG_TIMING_VTS, vts);\r
+}\r
+\r
+static int ov13850_get_light_freq(struct ov13850_dev *sensor)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_bandingfilter(struct ov13850_dev *sensor)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_ae_target(struct ov13850_dev *sensor, int target)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_get_binning(struct ov13850_dev *sensor)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_binning(struct ov13850_dev *sensor, bool enable)\r
+{\r
+       return 0;\r
+}\r
+\r
+static const struct ov13850_mode_info *\r
+ov13850_find_mode(struct ov13850_dev *sensor, enum ov13850_frame_rate fr,\r
+               int width, int height, bool nearest)\r
+{\r
+       const struct ov13850_mode_info *mode;\r
+\r
+       mode = v4l2_find_nearest_size(ov13850_mode_data,\r
+                               ARRAY_SIZE(ov13850_mode_data),\r
+                               hact, vact,\r
+                               width, height);\r
+\r
+       if (!mode ||\r
+               (!nearest && (mode->hact != width || mode->vact != height)))\r
+               return NULL;\r
+\r
+       /* Check to see if the current mode exceeds the max frame rate */\r
+       if (ov13850_framerates[fr] > ov13850_framerates[mode->max_fps])\r
+               return NULL;\r
+\r
+       return mode;\r
+}\r
+\r
+static u64 ov13850_calc_pixel_rate(struct ov13850_dev *sensor)\r
+{\r
+       u64 rate;\r
+\r
+       rate = sensor->current_mode->vact * sensor->current_mode->hact;\r
+       rate *= ov13850_framerates[sensor->current_fr];\r
+\r
+       return rate;\r
+}\r
+\r
+/*\r
+ * After trying the various combinations, reading various\r
+ * documentations spread around the net, and from the various\r
+ * feedback, the clock tree is probably as follows:\r
+ *\r
+ *   +--------------+\r
+ *   |  Ext. Clock  |\r
+ *   +-+------------+\r
+ *     |  +----------+\r
+ *     +->|   PLL1   | - reg 0x030a, bit0 for the pre-dividerp\r
+ *        +-+--------+ - reg 0x0300, bits 0-2 for the pre-divider\r
+ *        +-+--------+ - reg 0x0301~0x0302, for the multiplier\r
+ *          |  +--------------+\r
+ *          +->| MIPI Divider |  - reg 0x0303, bits 0-3 for the pre-divider\r
+ *               | +---------> MIPI PHY CLK\r
+ *               |    +-----+\r
+ *               | +->| PLL1_DIV_MIPI | - reg 0x0304, bits 0-1 for the divider\r
+ *                 |    +----------------> PCLK\r
+ *               |    +-----+\r
+ *\r
+ *   +--------------+\r
+ *   |  Ext. Clock  |\r
+ *   +-+------------+\r
+ *     |  +----------+\r
+ *     +->|   PLL2  | - reg 0x0311, bit0 for the pre-dividerp\r
+ *        +-+--------+ - reg 0x030b, bits 0-2 for the pre-divider\r
+ *        +-+--------+ - reg 0x030c~0x030d, for the multiplier\r
+ *          |  +--------------+\r
+ *          +->| SCLK Divider |  - reg 0x030F, bits 0-3 for the pre-divider\r
+ *               +-+--------+    - reg 0x030E, bits 0-2 for the divider\r
+ *               |    +---------> SCLK\r
+ *\r
+ *          |       +-----+\r
+ *          +->| DAC Divider | - reg 0x0312, bits 0-3 for the divider\r
+ *                    |    +----------------> DACCLK\r
+ **\r
+ */\r
+\r
+/*\r
+ * ov13850_set_mipi_pclk() - Calculate the clock tree configuration values\r
+ *                     for the MIPI CSI-2 output.\r
+ *\r
+ * @rate: The requested bandwidth per lane in bytes per second.\r
+ *     'Bandwidth Per Lane' is calculated as:\r
+ *     bpl = HTOT * VTOT * FPS * bpp / num_lanes;\r
+ *\r
+ * This function use the requested bandwidth to calculate:\r
+ *\r
+ * - mipi_pclk   = bpl / 2; ( / 2 is for CSI-2 DDR)\r
+ * - mipi_phy_clk   = mipi_pclk * PLL1_DIV_MIPI;\r
+ *\r
+ * with these fixed parameters:\r
+ *     PLL1_PREDIVP    = 1;\r
+ *     PLL1_PREDIV     = 1; (MIPI_BIT_MODE == 8 ? 2 : 2,5);\r
+ *     PLL1_DIVM       = 1;\r
+ *     PLL1_DIV_MIPI   = 4;\r
+ *\r
+ * FIXME: this have been tested with 10-bit raw and 2 lanes setup only.\r
+ * MIPI_DIV is fixed to value 2, but it -might- be changed according to the\r
+ * above formula for setups with 1 lane or image formats with different bpp.\r
+ *\r
+ * FIXME: this deviates from the sensor manual documentation which is quite\r
+ * thin on the MIPI clock tree generation part.\r
+ */\r
+\r
+\r
+\r
+static int ov13850_set_mipi_pclk(struct ov13850_dev *sensor,\r
+                               unsigned long rate)\r
+{\r
+\r
+       return 0;\r
+}\r
+\r
+/*\r
+ * if sensor changes inside scaling or subsampling\r
+ * change mode directly\r
+ */\r
+static int ov13850_set_mode_direct(struct ov13850_dev *sensor,\r
+                               const struct ov13850_mode_info *mode)\r
+{\r
+       if (!mode->reg_data)\r
+               return -EINVAL;\r
+\r
+       /* Write capture setting */\r
+       return ov13850_load_regs(sensor, mode);\r
+}\r
+\r
+static int ov13850_set_mode(struct ov13850_dev *sensor)\r
+{\r
+       const struct ov13850_mode_info *mode = sensor->current_mode;\r
+       const struct ov13850_mode_info *orig_mode = sensor->last_mode;\r
+       int ret = 0;\r
+\r
+       ret = ov13850_set_mode_direct(sensor, mode);\r
+       if (ret < 0)\r
+               return ret;\r
+\r
+       /*\r
+        * we support have 10 bits raw RGB(mipi)\r
+        */\r
+       if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)\r
+               ret = ov13850_set_mipi_pclk(sensor, 0);\r
+\r
+       if (ret < 0)\r
+               return 0;\r
+\r
+       sensor->pending_mode_change = false;\r
+       sensor->last_mode = mode;\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_framefmt(struct ov13850_dev *sensor,\r
+                              struct v4l2_mbus_framefmt *format);\r
+\r
+/* restore the last set video mode after chip power-on */\r
+static int ov13850_restore_mode(struct ov13850_dev *sensor)\r
+{\r
+       int ret;\r
+\r
+       /* first load the initial register values */\r
+       ret = ov13850_load_regs(sensor, &ov13850_mode_init_data);\r
+       if (ret < 0)\r
+               return ret;\r
+       sensor->last_mode = &ov13850_mode_init_data;\r
+\r
+       /* now restore the last capture mode */\r
+       ret = ov13850_set_mode(sensor);\r
+       if (ret < 0)\r
+               return ret;\r
+\r
+       return ov13850_set_framefmt(sensor, &sensor->fmt);\r
+}\r
+\r
+static void ov13850_power(struct ov13850_dev *sensor, bool enable)\r
+{\r
+       if (!sensor->pwdn_gpio)\r
+               return;\r
+       if (enable) {\r
+               gpiod_set_value_cansleep(sensor->pwdn_gpio, 0);\r
+               gpiod_set_value_cansleep(sensor->pwdn_gpio, 1);\r
+       } else {\r
+               gpiod_set_value_cansleep(sensor->pwdn_gpio, 0);\r
+       }\r
+\r
+       mdelay(100);\r
+}\r
+\r
+static void ov13850_reset(struct ov13850_dev *sensor)\r
+{\r
+       if (!sensor->reset_gpio)\r
+               return;\r
+\r
+       gpiod_set_value_cansleep(sensor->reset_gpio, 0);\r
+       gpiod_set_value_cansleep(sensor->reset_gpio, 1);\r
+       mdelay(100);\r
+}\r
+\r
+static int ov13850_set_power_on(struct ov13850_dev *sensor)\r
+{\r
+       struct i2c_client *client = sensor->i2c_client;\r
+       int ret;\r
+\r
+       ret = clk_prepare_enable(sensor->xclk);\r
+       if (ret) {\r
+               dev_err(&client->dev, "%s: failed to enable clock\n",\r
+                       __func__);\r
+               return ret;\r
+       }\r
+\r
+       ret = regulator_bulk_enable(OV13850_NUM_SUPPLIES,\r
+                               sensor->supplies);\r
+       if (ret) {\r
+               dev_err(&client->dev, "%s: failed to enable regulators\n",\r
+                       __func__);\r
+               goto xclk_off;\r
+       }\r
+\r
+       ov13850_reset(sensor);\r
+       ov13850_power(sensor, true);\r
+\r
+       return 0;\r
+\r
+xclk_off:\r
+       clk_disable_unprepare(sensor->xclk);\r
+       return ret;\r
+}\r
+\r
+static void ov13850_set_power_off(struct ov13850_dev *sensor)\r
+{\r
+       ov13850_power(sensor, false);\r
+       regulator_bulk_disable(OV13850_NUM_SUPPLIES, sensor->supplies);\r
+       clk_disable_unprepare(sensor->xclk);\r
+}\r
+\r
+static int ov13850_set_power_mipi(struct ov13850_dev *sensor, bool on)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_power(struct ov13850_dev *sensor, bool on)\r
+{\r
+       int ret = 0;\r
+       u16 chip_id;\r
+\r
+       if (on) {\r
+               ret = ov13850_set_power_on(sensor);\r
+               if (ret)\r
+                       return ret;\r
+\r
+#if 0\r
+               ret = ov13850_read_reg16(sensor, OV13850_REG_CHIP_ID, &chip_id);\r
+               if (ret) {\r
+                       dev_err(&sensor->i2c_client->dev, "%s: failed to read chip identifier\n",\r
+                               __func__);\r
+                       ret = -ENODEV;\r
+                       goto power_off;\r
+               }\r
+\r
+               if (chip_id != OV13850_CHIP_ID) {\r
+                       dev_err(&sensor->i2c_client->dev,\r
+                                       "%s: wrong chip identifier, expected 0x%x, got 0x%x\n",\r
+                                       __func__, OV13850_CHIP_ID, chip_id);\r
+                       ret = -ENXIO;\r
+                       goto power_off;\r
+               }\r
+               dev_err(&sensor->i2c_client->dev, "%s: chip identifier, got 0x%x\n",\r
+                       __func__, chip_id);\r
+#endif\r
+\r
+               ret = ov13850_restore_mode(sensor);\r
+               if (ret)\r
+                       goto power_off;\r
+       }\r
+\r
+       if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)\r
+               ret = ov13850_set_power_mipi(sensor, on);\r
+       if (ret)\r
+               goto power_off;\r
+\r
+       if (!on)\r
+               ov13850_set_power_off(sensor);\r
+\r
+       return 0;\r
+\r
+power_off:\r
+       ov13850_set_power_off(sensor);\r
+       return ret;\r
+}\r
+\r
+static int ov13850_s_power(struct v4l2_subdev *sd, int on)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       int ret = 0;\r
+\r
+       mutex_lock(&sensor->lock);\r
+\r
+       /*\r
+        * If the power count is modified from 0 to != 0 or from != 0 to 0,\r
+        * update the power state.\r
+        */\r
+       if (sensor->power_count == !on) {\r
+               ret = ov13850_set_power(sensor, !!on);\r
+               if (ret)\r
+                       goto out;\r
+       }\r
+\r
+       /* Update the power count. */\r
+       sensor->power_count += on ? 1 : -1;\r
+       WARN_ON(sensor->power_count < 0);\r
+out:\r
+       mutex_unlock(&sensor->lock);\r
+\r
+       if (on && !ret && sensor->power_count == 1) {\r
+               /* restore controls */\r
+               ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+static int ov13850_try_frame_interval(struct ov13850_dev *sensor,\r
+                               struct v4l2_fract *fi,\r
+                               u32 width, u32 height)\r
+{\r
+       const struct ov13850_mode_info *mode;\r
+       enum ov13850_frame_rate rate = OV13850_15_FPS;\r
+       int minfps, maxfps, best_fps, fps;\r
+       int i;\r
+\r
+       minfps = ov13850_framerates[OV13850_15_FPS];\r
+       maxfps = ov13850_framerates[OV13850_NUM_FRAMERATES - 1];\r
+\r
+       if (fi->numerator == 0) {\r
+               fi->denominator = maxfps;\r
+               fi->numerator = 1;\r
+               rate = OV13850_60_FPS;\r
+               goto find_mode;\r
+       }\r
+\r
+       fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),\r
+                       minfps, maxfps);\r
+\r
+       best_fps = minfps;\r
+       for (i = 0; i < ARRAY_SIZE(ov13850_framerates); i++) {\r
+               int curr_fps = ov13850_framerates[i];\r
+               if (abs(curr_fps - fps) < abs(best_fps - fps)) {\r
+                       best_fps = curr_fps;\r
+                       rate = i;\r
+               }\r
+       }\r
+       st_info(ST_SENSOR, "best_fps = %d, fps = %d\n", best_fps, fps);\r
+\r
+       fi->numerator = 1;\r
+       fi->denominator = best_fps;\r
+\r
+find_mode:\r
+       mode = ov13850_find_mode(sensor, rate, width, height, false);\r
+       return mode ? rate : -EINVAL;\r
+}\r
+\r
+static int ov13850_enum_mbus_code(struct v4l2_subdev *sd,\r
+                               struct v4l2_subdev_state *state,\r
+                               struct v4l2_subdev_mbus_code_enum *code)\r
+{\r
+       if (code->pad != 0)\r
+               return -EINVAL;\r
+\r
+       if (code->index >= ARRAY_SIZE(ov13850_formats))\r
+               return -EINVAL;\r
+\r
+       code->code = ov13850_formats[code->index].code;\r
+       return 0;\r
+}\r
+\r
+static int ov13850_get_fmt(struct v4l2_subdev *sd,\r
+                       struct v4l2_subdev_state *state,\r
+                       struct v4l2_subdev_format *format)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       struct v4l2_mbus_framefmt *fmt;\r
+\r
+       if (format->pad != 0)\r
+               return -EINVAL;\r
+\r
+       mutex_lock(&sensor->lock);\r
+\r
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY)\r
+               fmt = v4l2_subdev_get_try_format(&sensor->sd, state,\r
+                                               format->pad);\r
+       else\r
+               fmt = &sensor->fmt;\r
+\r
+       format->format = *fmt;\r
+\r
+       mutex_unlock(&sensor->lock);\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_try_fmt_internal(struct v4l2_subdev *sd,\r
+                               struct v4l2_mbus_framefmt *fmt,\r
+                               enum ov13850_frame_rate fr,\r
+                               const struct ov13850_mode_info **new_mode)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       const struct ov13850_mode_info *mode;\r
+       int i;\r
+\r
+       mode = ov13850_find_mode(sensor, fr, fmt->width, fmt->height, true);\r
+       if (!mode)\r
+               return -EINVAL;\r
+       fmt->width = mode->hact;\r
+       fmt->height = mode->vact;\r
+\r
+       if (new_mode)\r
+               *new_mode = mode;\r
+\r
+       for (i = 0; i < ARRAY_SIZE(ov13850_formats); i++)\r
+               if (ov13850_formats[i].code == fmt->code)\r
+                       break;\r
+       if (i >= ARRAY_SIZE(ov13850_formats))\r
+               i = 0;\r
+\r
+       fmt->code = ov13850_formats[i].code;\r
+       fmt->colorspace = ov13850_formats[i].colorspace;\r
+       fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);\r
+       fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;\r
+       fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_fmt(struct v4l2_subdev *sd,\r
+                       struct v4l2_subdev_state *state,\r
+                       struct v4l2_subdev_format *format)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       const struct ov13850_mode_info *new_mode;\r
+       struct v4l2_mbus_framefmt *mbus_fmt = &format->format;\r
+       struct v4l2_mbus_framefmt *fmt;\r
+       int ret;\r
+\r
+       if (format->pad != 0)\r
+               return -EINVAL;\r
+\r
+       mutex_lock(&sensor->lock);\r
+\r
+       if (sensor->streaming) {\r
+               ret = -EBUSY;\r
+               goto out;\r
+       }\r
+\r
+       ret = ov13850_try_fmt_internal(sd, mbus_fmt, 0, &new_mode);\r
+       if (ret)\r
+               goto out;\r
+\r
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY)\r
+               fmt = v4l2_subdev_get_try_format(sd, state, 0);\r
+       else\r
+               fmt = &sensor->fmt;\r
+\r
+    if (mbus_fmt->code != sensor->fmt.code)\r
+               sensor->pending_fmt_change = true;\r
+\r
+       *fmt = *mbus_fmt;\r
+\r
+       if (new_mode != sensor->current_mode) {\r
+               sensor->current_mode = new_mode;\r
+               sensor->pending_mode_change = true;\r
+       }\r
+       if (new_mode->max_fps < sensor->current_fr) {\r
+               sensor->current_fr = new_mode->max_fps;\r
+               sensor->frame_interval.numerator = 1;\r
+               sensor->frame_interval.denominator =\r
+                       ov13850_framerates[sensor->current_fr];\r
+               sensor->current_mode = new_mode;\r
+               sensor->pending_mode_change = true;\r
+       }\r
+\r
+       __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,\r
+                               ov13850_calc_pixel_rate(sensor));\r
+out:\r
+       mutex_unlock(&sensor->lock);\r
+       return ret;\r
+}\r
+\r
+static int ov13850_set_framefmt(struct ov13850_dev *sensor,\r
+                              struct v4l2_mbus_framefmt *format)\r
+{\r
+       u8 fmt;\r
+\r
+       switch (format->code) {\r
+    /* Raw, BGBG... / GRGR... */\r
+       case MEDIA_BUS_FMT_SBGGR8_1X8:\r
+    case MEDIA_BUS_FMT_SGBRG8_1X8:\r
+       case MEDIA_BUS_FMT_SGRBG8_1X8:\r
+       case MEDIA_BUS_FMT_SRGGB8_1X8:\r
+               fmt = 0x0;\r
+               break;\r
+    case MEDIA_BUS_FMT_SBGGR10_1X10:\r
+    case MEDIA_BUS_FMT_SGBRG10_1X10:\r
+       case MEDIA_BUS_FMT_SGRBG10_1X10:\r
+       case MEDIA_BUS_FMT_SRGGB10_1X10:\r
+        fmt = 0x1;\r
+    case MEDIA_BUS_FMT_SBGGR12_1X12:\r
+    case MEDIA_BUS_FMT_SGBRG12_1X12:\r
+       case MEDIA_BUS_FMT_SGRBG12_1X12:\r
+       case MEDIA_BUS_FMT_SRGGB12_1X12:\r
+        fmt = 0x2;\r
+       default:\r
+               return -EINVAL;\r
+       }\r
+\r
+       return ov13850_mod_reg(sensor, OV13850_REG_MIPI_SC,\r
+                             BIT(1) | BIT(0), fmt);\r
+}\r
+\r
+/*\r
+ * Sensor Controls.\r
+ */\r
+\r
+static int ov13850_set_ctrl_hue(struct ov13850_dev *sensor, int value)\r
+{\r
+       int ret = 0;\r
+\r
+       return ret;\r
+}\r
+\r
+static int ov13850_set_ctrl_contrast(struct ov13850_dev *sensor, int value)\r
+{\r
+       int ret = 0;\r
+\r
+       return ret;\r
+}\r
+\r
+static int ov13850_set_ctrl_saturation(struct ov13850_dev *sensor, int value)\r
+{\r
+       int ret  = 0;\r
+\r
+       return ret;\r
+}\r
+\r
+static int ov13850_set_ctrl_white_balance(struct ov13850_dev *sensor, int awb)\r
+{\r
+       struct ov13850_ctrls *ctrls = &sensor->ctrls;\r
+       int ret = 0;\r
+\r
+       return ret;\r
+}\r
+\r
+static int ov13850_set_ctrl_exposure(struct ov13850_dev *sensor,\r
+                               enum v4l2_exposure_auto_type auto_exposure)\r
+{\r
+       struct ov13850_ctrls *ctrls = &sensor->ctrls;\r
+       int ret = 0;\r
+\r
+       return ret;\r
+}\r
+\r
+static const s64 link_freq_menu_items[] = {\r
+       OV13850_LINK_FREQ_500MHZ\r
+};\r
+\r
+static const char * const test_pattern_menu[] = {\r
+       "Disabled",\r
+       "Color bars",\r
+       "Color bars w/ rolling bar",\r
+       "Color squares",\r
+       "Color squares w/ rolling bar",\r
+};\r
+\r
+static int ov13850_set_ctrl_test_pattern(struct ov13850_dev *sensor, int value)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_ctrl_light_freq(struct ov13850_dev *sensor, int value)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_ctrl_hflip(struct ov13850_dev *sensor, int value)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_set_ctrl_vflip(struct ov13850_dev *sensor, int value)\r
+{\r
+       return 0;\r
+}\r
+\r
+static int ov13850_g_volatile_ctrl(struct v4l2_ctrl *ctrl)\r
+{\r
+       struct v4l2_subdev *sd = ctrl_to_sd(ctrl);\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       int val;\r
+\r
+       /* v4l2_ctrl_lock() locks our own mutex */\r
+\r
+       switch (ctrl->id) {\r
+       case V4L2_CID_ANALOGUE_GAIN:\r
+               val = ov13850_get_gain(sensor);\r
+               break;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_s_ctrl(struct v4l2_ctrl *ctrl)\r
+{\r
+       struct v4l2_subdev *sd = ctrl_to_sd(ctrl);\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       int ret;\r
+\r
+       /* v4l2_ctrl_lock() locks our own mutex */\r
+\r
+       /*\r
+        * If the device is not powered up by the host driver do\r
+        * not apply any controls to H/W at this time. Instead\r
+        * the controls will be restored right after power-up.\r
+        */\r
+       if (sensor->power_count == 0)\r
+               return 0;\r
+\r
+       switch (ctrl->id) {\r
+       case V4L2_CID_ANALOGUE_GAIN:\r
+               ret = ov13850_set_gain(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_EXPOSURE:\r
+               ret = ov13850_set_ctrl_exposure(sensor, V4L2_EXPOSURE_MANUAL);\r
+               break;\r
+       case V4L2_CID_AUTO_WHITE_BALANCE:\r
+               ret = ov13850_set_ctrl_white_balance(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_HUE:\r
+               ret = ov13850_set_ctrl_hue(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_CONTRAST:\r
+               ret = ov13850_set_ctrl_contrast(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_SATURATION:\r
+               ret = ov13850_set_ctrl_saturation(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_TEST_PATTERN:\r
+               ret = ov13850_set_ctrl_test_pattern(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_POWER_LINE_FREQUENCY:\r
+               ret = ov13850_set_ctrl_light_freq(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_HFLIP:\r
+               ret = ov13850_set_ctrl_hflip(sensor, ctrl->val);\r
+               break;\r
+       case V4L2_CID_VFLIP:\r
+               ret = ov13850_set_ctrl_vflip(sensor, ctrl->val);\r
+               break;\r
+       default:\r
+               ret = -EINVAL;\r
+               break;\r
+       }\r
+\r
+       return ret;\r
+}\r
+\r
+static const struct v4l2_ctrl_ops ov13850_ctrl_ops = {\r
+       .g_volatile_ctrl = ov13850_g_volatile_ctrl,\r
+       .s_ctrl = ov13850_s_ctrl,\r
+};\r
+\r
+static int ov13850_init_controls(struct ov13850_dev *sensor)\r
+{\r
+       const struct v4l2_ctrl_ops *ops = &ov13850_ctrl_ops;\r
+       struct ov13850_ctrls *ctrls = &sensor->ctrls;\r
+       struct v4l2_ctrl_handler *hdl = &ctrls->handler;\r
+       int ret;\r
+\r
+       v4l2_ctrl_handler_init(hdl, 32);\r
+\r
+       /* we can use our own mutex for the ctrl lock */\r
+       hdl->lock = &sensor->lock;\r
+\r
+       /* Clock related controls */\r
+       ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,\r
+                                       0, INT_MAX, 1,\r
+                                       ov13850_calc_pixel_rate(sensor));\r
+\r
+       /* Auto/manual white balance */\r
+       ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,\r
+                                       V4L2_CID_AUTO_WHITE_BALANCE,\r
+                                       0, 1, 1, 0);\r
+       ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,\r
+                                               0, 4095, 1, 1024);\r
+       ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,\r
+                                               0, 4095, 1, 1024);\r
+\r
+       ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,\r
+                                       4, 0xfff8, 1, 0x4c00);\r
+       ctrls->anal_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN,\r
+                                       0x10, 0xfff8, 1, 0x0080);\r
+       ctrls->test_pattern =\r
+               v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,\r
+                                       ARRAY_SIZE(test_pattern_menu) - 1,\r
+                                       0, 0, test_pattern_menu);\r
+       ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,\r
+                                       0, 1, 1, 0);\r
+       ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,\r
+                                       0, 1, 1, 0);\r
+       ctrls->light_freq =\r
+               v4l2_ctrl_new_std_menu(hdl, ops,\r
+                                       V4L2_CID_POWER_LINE_FREQUENCY,\r
+                                       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,\r
+                                       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);\r
+       ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ,\r
+                                       0, 0, link_freq_menu_items);\r
+       if (hdl->error) {\r
+               ret = hdl->error;\r
+               goto free_ctrls;\r
+       }\r
+\r
+       ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;\r
+       ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;\r
+       // ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;\r
+       // ctrls->anal_gain->flags |= V4L2_CTRL_FLAG_VOLATILE;\r
+\r
+       v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);\r
+\r
+       sensor->sd.ctrl_handler = hdl;\r
+       return 0;\r
+\r
+free_ctrls:\r
+       v4l2_ctrl_handler_free(hdl);\r
+       return ret;\r
+}\r
+\r
+static int ov13850_enum_frame_size(struct v4l2_subdev *sd,\r
+                               struct v4l2_subdev_state *state,\r
+                               struct v4l2_subdev_frame_size_enum *fse)\r
+{\r
+       if (fse->pad != 0)\r
+               return -EINVAL;\r
+       if (fse->index >= OV13850_NUM_MODES)\r
+               return -EINVAL;\r
+\r
+       fse->min_width =\r
+               ov13850_mode_data[fse->index].hact;\r
+       fse->max_width = fse->min_width;\r
+       fse->min_height =\r
+               ov13850_mode_data[fse->index].vact;\r
+       fse->max_height = fse->min_height;\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_enum_frame_interval(\r
+       struct v4l2_subdev *sd,\r
+       struct v4l2_subdev_state *state,\r
+       struct v4l2_subdev_frame_interval_enum *fie)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       struct v4l2_fract tpf;\r
+       int ret;\r
+\r
+       if (fie->pad != 0)\r
+               return -EINVAL;\r
+       if (fie->index >= OV13850_NUM_FRAMERATES)\r
+               return -EINVAL;\r
+\r
+       tpf.numerator = 1;\r
+       tpf.denominator = ov13850_framerates[fie->index];\r
+\r
+/*     ret = ov13850_try_frame_interval(sensor, &tpf,\r
+                                       fie->width, fie->height);\r
+       if (ret < 0)\r
+               return -EINVAL;\r
+*/\r
+       fie->interval = tpf;\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_g_frame_interval(struct v4l2_subdev *sd,\r
+                               struct v4l2_subdev_frame_interval *fi)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+\r
+       mutex_lock(&sensor->lock);\r
+       fi->interval = sensor->frame_interval;\r
+       mutex_unlock(&sensor->lock);\r
+\r
+       return 0;\r
+}\r
+\r
+static int ov13850_s_frame_interval(struct v4l2_subdev *sd,\r
+                               struct v4l2_subdev_frame_interval *fi)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       const struct ov13850_mode_info *mode;\r
+       int frame_rate, ret = 0;\r
+\r
+       if (fi->pad != 0)\r
+               return -EINVAL;\r
+\r
+       mutex_lock(&sensor->lock);\r
+\r
+       if (sensor->streaming) {\r
+               ret = -EBUSY;\r
+               goto out;\r
+       }\r
+\r
+       mode = sensor->current_mode;\r
+\r
+       frame_rate = ov13850_try_frame_interval(sensor, &fi->interval,\r
+                                       mode->hact, mode->vact);\r
+       if (frame_rate < 0) {\r
+               /* Always return a valid frame interval value */\r
+               fi->interval = sensor->frame_interval;\r
+               goto out;\r
+       }\r
+\r
+       mode = ov13850_find_mode(sensor, frame_rate, mode->hact,\r
+                               mode->vact, true);\r
+       if (!mode) {\r
+               ret = -EINVAL;\r
+               goto out;\r
+       }\r
+\r
+       if (mode != sensor->current_mode ||\r
+               frame_rate != sensor->current_fr) {\r
+               sensor->current_fr = frame_rate;\r
+               sensor->frame_interval = fi->interval;\r
+               sensor->current_mode = mode;\r
+               sensor->pending_mode_change = true;\r
+\r
+               __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,\r
+                                       ov13850_calc_pixel_rate(sensor));\r
+       }\r
+out:\r
+       mutex_unlock(&sensor->lock);\r
+       return ret;\r
+}\r
+\r
+static int ov13850_stream_start(struct ov13850_dev *sensor, int enable)\r
+{\r
+    int ret;\r
+\r
+    if (enable) {       //stream on\r
+        mdelay(1000);\r
+           ret = ov13850_write_reg(sensor, OV13850_STREAM_CTRL, enable);\r
+    } else {            //stream off\r
+        ret = ov13850_write_reg(sensor, OV13850_STREAM_CTRL, enable);\r
+        mdelay(100);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+static int ov13850_s_stream(struct v4l2_subdev *sd, int enable)\r
+{\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+       int ret = 0;\r
+\r
+       mutex_lock(&sensor->lock);\r
+\r
+       if (sensor->streaming == !enable) {\r
+               if (enable && sensor->pending_mode_change) {\r
+                       ret = ov13850_set_mode(sensor);\r
+                       if (ret)\r
+                               goto out;\r
+               }\r
+\r
+               if (enable && sensor->pending_fmt_change) {\r
+                       ret = ov13850_set_framefmt(sensor, &sensor->fmt);\r
+                       if (ret)\r
+                               goto out;\r
+                       sensor->pending_fmt_change = false;\r
+               }\r
+\r
+               if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)\r
+                       ret = ov13850_set_stream_mipi(sensor, enable);\r
+\r
+               ret = ov13850_stream_start(sensor, enable);\r
+\r
+               if (!ret)\r
+                       sensor->streaming = enable;\r
+       }\r
+out:\r
+       mutex_unlock(&sensor->lock);\r
+       return ret;\r
+}\r
+\r
+static const struct v4l2_subdev_core_ops ov13850_core_ops = {\r
+       .s_power = ov13850_s_power,\r
+       .log_status = v4l2_ctrl_subdev_log_status,\r
+       .subscribe_event = v4l2_ctrl_subdev_subscribe_event,\r
+       .unsubscribe_event = v4l2_event_subdev_unsubscribe,\r
+};\r
+\r
+static const struct v4l2_subdev_video_ops ov13850_video_ops = {\r
+       .g_frame_interval = ov13850_g_frame_interval,\r
+       .s_frame_interval = ov13850_s_frame_interval,\r
+       .s_stream = ov13850_s_stream,\r
+};\r
+\r
+static const struct v4l2_subdev_pad_ops ov13850_pad_ops = {\r
+       .enum_mbus_code = ov13850_enum_mbus_code,\r
+       .get_fmt = ov13850_get_fmt,\r
+       .set_fmt = ov13850_set_fmt,\r
+       .enum_frame_size = ov13850_enum_frame_size,\r
+       .enum_frame_interval = ov13850_enum_frame_interval,\r
+};\r
+\r
+static const struct v4l2_subdev_ops ov13850_subdev_ops = {\r
+       .core = &ov13850_core_ops,\r
+       .video = &ov13850_video_ops,\r
+       .pad = &ov13850_pad_ops,\r
+};\r
+\r
+static int ov13850_get_regulators(struct ov13850_dev *sensor)\r
+{\r
+       int i;\r
+\r
+       for (i = 0; i < OV13850_NUM_SUPPLIES; i++)\r
+               sensor->supplies[i].supply = ov13850_supply_name[i];\r
+\r
+       return devm_regulator_bulk_get(&sensor->i2c_client->dev,\r
+                                       OV13850_NUM_SUPPLIES,\r
+                                       sensor->supplies);\r
+}\r
+\r
+static int ov13850_check_chip_id(struct ov13850_dev *sensor)\r
+{\r
+       struct i2c_client *client = sensor->i2c_client;\r
+       int ret = 0;\r
+       u16 chip_id;\r
+\r
+       ret = ov13850_set_power_on(sensor);\r
+       if (ret)\r
+               return ret;\r
+\r
+#if 0\r
+       ret = ov13850_read_reg16(sensor, OV13850_REG_CHIP_ID, &chip_id);\r
+       if (ret) {\r
+               dev_err(&client->dev, "%s: failed to read chip identifier\n",\r
+                       __func__);\r
+               goto power_off;\r
+       }\r
+\r
+       if (chip_id != OV13850_CHIP_ID) {\r
+               dev_err(&client->dev, "%s: wrong chip identifier, expected 0x%x,  got 0x%x\n",\r
+                       __func__, OV13850_CHIP_ID, chip_id);\r
+               ret = -ENXIO;\r
+       }\r
+       dev_err(&client->dev, "%s: chip identifier, got 0x%x\n",\r
+               __func__, chip_id);\r
+#endif\r
+\r
+power_off:\r
+       ov13850_set_power_off(sensor);\r
+       return ret;\r
+}\r
+\r
+static int ov13850_probe(struct i2c_client *client)\r
+{\r
+       struct device *dev = &client->dev;\r
+       struct fwnode_handle *endpoint;\r
+       struct ov13850_dev *sensor;\r
+       struct v4l2_mbus_framefmt *fmt;\r
+       u32 rotation;\r
+       int ret;\r
+       u8 chip_id_high, chip_id_low;\r
+\r
+       sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);\r
+       if (!sensor)\r
+               return -ENOMEM;\r
+\r
+       sensor->i2c_client = client;\r
+\r
+       fmt = &sensor->fmt;\r
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;\r
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;\r
+       fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);\r
+       fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;\r
+       fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);\r
+       fmt->width = 1920;\r
+       fmt->height = 1080;\r
+       fmt->field = V4L2_FIELD_NONE;\r
+       sensor->frame_interval.numerator = 1;\r
+       sensor->frame_interval.denominator = ov13850_framerates[OV13850_30_FPS];\r
+       sensor->current_fr = OV13850_30_FPS;\r
+       sensor->current_mode =\r
+               &ov13850_mode_data[OV13850_MODE_1080P_1920_1080];\r
+       sensor->last_mode = sensor->current_mode;\r
+\r
+       sensor->ae_target = 52;\r
+\r
+       /* optional indication of physical rotation of sensor */\r
+       ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",\r
+                                       &rotation);\r
+       if (!ret) {\r
+               switch (rotation) {\r
+               case 180:\r
+                       sensor->upside_down = true;\r
+                       fallthrough;\r
+               case 0:\r
+                       break;\r
+               default:\r
+                       dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",\r
+                               rotation);\r
+               }\r
+       }\r
+\r
+       endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),\r
+                                               NULL);\r
+       if (!endpoint) {\r
+               dev_err(dev, "endpoint node not found\n");\r
+               return -EINVAL;\r
+       }\r
+\r
+       ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);\r
+       fwnode_handle_put(endpoint);\r
+       if (ret) {\r
+               dev_err(dev, "Could not parse endpoint\n");\r
+               return ret;\r
+       }\r
+\r
+       if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&\r
+               sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&\r
+               sensor->ep.bus_type != V4L2_MBUS_BT656) {\r
+               dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);\r
+               return -EINVAL;\r
+       }\r
+\r
+       /* get system clock (xclk) */\r
+       sensor->xclk = devm_clk_get(dev, "xclk");\r
+       if (IS_ERR(sensor->xclk)) {\r
+               dev_err(dev, "failed to get xclk\n");\r
+               return PTR_ERR(sensor->xclk);\r
+       }\r
+\r
+       sensor->xclk_freq = clk_get_rate(sensor->xclk);\r
+       if (sensor->xclk_freq < OV13850_XCLK_MIN ||\r
+               sensor->xclk_freq > OV13850_XCLK_MAX) {\r
+               dev_err(dev, "xclk frequency out of range: %d Hz\n",\r
+                       sensor->xclk_freq);\r
+               return -EINVAL;\r
+       }\r
+\r
+       /* request optional power down pin */\r
+       sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",\r
+                                               GPIOD_OUT_HIGH);\r
+       if (IS_ERR(sensor->pwdn_gpio))\r
+               return PTR_ERR(sensor->pwdn_gpio);\r
+\r
+       /* request optional reset pin */\r
+       sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",\r
+                                               GPIOD_OUT_HIGH);\r
+       if (IS_ERR(sensor->reset_gpio))\r
+               return PTR_ERR(sensor->reset_gpio);\r
+\r
+       v4l2_i2c_subdev_init(&sensor->sd, client, &ov13850_subdev_ops);\r
+\r
+       sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |\r
+                       V4L2_SUBDEV_FL_HAS_EVENTS;\r
+       sensor->pad.flags = MEDIA_PAD_FL_SOURCE;\r
+       sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;\r
+       ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);\r
+       if (ret)\r
+               return ret;\r
+\r
+       ret = ov13850_get_regulators(sensor);\r
+       if (ret)\r
+               return ret;\r
+\r
+       mutex_init(&sensor->lock);\r
+\r
+       ret = ov13850_check_chip_id(sensor);\r
+       if (ret)\r
+               goto entity_cleanup;\r
+\r
+       ret = ov13850_init_controls(sensor);\r
+       if (ret)\r
+               goto entity_cleanup;\r
+\r
+       ret = v4l2_async_register_subdev_sensor(&sensor->sd);\r
+       if (ret)\r
+               goto free_ctrls;\r
+\r
+       return 0;\r
+\r
+free_ctrls:\r
+       v4l2_ctrl_handler_free(&sensor->ctrls.handler);\r
+entity_cleanup:\r
+       media_entity_cleanup(&sensor->sd.entity);\r
+       mutex_destroy(&sensor->lock);\r
+       return ret;\r
+}\r
+\r
+static int ov13850_remove(struct i2c_client *client)\r
+{\r
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);\r
+       struct ov13850_dev *sensor = to_ov13850_dev(sd);\r
+\r
+       v4l2_async_unregister_subdev(&sensor->sd);\r
+       media_entity_cleanup(&sensor->sd.entity);\r
+       v4l2_ctrl_handler_free(&sensor->ctrls.handler);\r
+       mutex_destroy(&sensor->lock);\r
+\r
+       return 0;\r
+}\r
+\r
+static const struct i2c_device_id ov13850_id[] = {\r
+       {"ov13850", 0},\r
+       {},\r
+};\r
+MODULE_DEVICE_TABLE(i2c, ov13850_id);\r
+\r
+static const struct of_device_id ov13850_dt_ids[] = {\r
+       { .compatible = "ovti,ov13850" },\r
+       { /* sentinel */ }\r
+};\r
+MODULE_DEVICE_TABLE(of, ov13850_dt_ids);\r
+\r
+static struct i2c_driver ov13850_i2c_driver = {\r
+       .driver = {\r
+               .name  = "ov13850",\r
+               .of_match_table = ov13850_dt_ids,\r
+       },\r
+       .id_table = ov13850_id,\r
+       .probe_new = ov13850_probe,\r
+       .remove   = ov13850_remove,\r
+};\r
+\r
+module_i2c_driver(ov13850_i2c_driver);\r
+\r
+MODULE_DESCRIPTION("OV13850 MIPI Camera Subdev Driver");\r
+MODULE_LICENSE("GPL");\r
index 240a7f0..56f2d8c 100755 (executable)
@@ -37,6 +37,7 @@
 
 static int apb_clk_set(struct stf_vin_dev *vin, int on)
 {
+#if 0
        static int init_flag;
        static struct mutex count_lock;
        static int count;
@@ -61,13 +62,15 @@ static int apb_clk_set(struct stf_vin_dev *vin, int on)
        }
 exit:
        mutex_unlock(&count_lock);
-       return 0;
+#endif
 
+       return 0;
 }
 static int stf_csi_clk_enable(struct stf_csi_dev *csi_dev)
 {
        struct stf_vin_dev *vin = csi_dev->stfcamss->vin;
 
+#if 0
        // reg_set_highest_bit(vin->clkgen_base, CLK_CSI2RX0_APB_CTRL);
        apb_clk_set(vin, 1);
 
@@ -90,6 +93,7 @@ static int stf_csi_clk_enable(struct stf_csi_dev *csi_dev)
                reg_set_highest_bit(vin->clkgen_base, CLK_MIPI_RX1_PXL_3_CTRL);
                reg_set_highest_bit(vin->clkgen_base, CLK_MIPI_RX1_SYS1_CTRL);
        }
+#endif
 
        return 0;
 }
@@ -98,6 +102,7 @@ static int stf_csi_clk_disable(struct stf_csi_dev *csi_dev)
 {
        struct stf_vin_dev *vin = csi_dev->stfcamss->vin;
 
+#if 0
        // reg_clr_highest_bit(vin->clkgen_base, CLK_CSI2RX0_APB_CTRL);
        apb_clk_set(vin, 0);
 
@@ -114,6 +119,7 @@ static int stf_csi_clk_disable(struct stf_csi_dev *csi_dev)
                reg_clr_highest_bit(vin->clkgen_base, CLK_MIPI_RX1_PXL_3_CTRL);
                reg_clr_highest_bit(vin->clkgen_base, CLK_MIPI_RX1_SYS1_CTRL);
        }
+#endif
 
        return 0;
 }
@@ -235,7 +241,7 @@ static void csi2rx_debug_config(void *reg_base, u32 frame_lines)
        reg_write(reg_base, STREAM0_FCC_CTRL, (0x0 << 1) | 0x1);
 }
 
-static int csi2rx_start(struct stf_csi_dev *csi_dev)
+static int csi2rx_start(struct stf_csi_dev *csi_dev, void *reg_base)
 {
        struct stfcamss *stfcamss = csi_dev->stfcamss;
        struct stf_vin_dev *vin = stfcamss->vin;
@@ -245,7 +251,6 @@ static int csi2rx_start(struct stf_csi_dev *csi_dev)
        unsigned long lanes_used = 0;
        u32 reg;
        int ret;
-       void *reg_base = NULL;
 
        if (!csiphy) {
                st_err(ST_CSI, "csiphy%d sensor not exist use csiphy%d init.\n",
@@ -258,13 +263,6 @@ static int csi2rx_start(struct stf_csi_dev *csi_dev)
                }
        }
 
-       if (csi_dev->id == 0)
-               reg_base = vin->mipi0_base;
-       else if (csi_dev->id == 1)
-               reg_base = vin->mipi1_base;
-       else
-               return 0;
-
        csi2rx_reset(reg_base);
 
        reg = csiphy->num_data_lanes << 8;
@@ -302,7 +300,7 @@ static int csi2rx_start(struct stf_csi_dev *csi_dev)
                        | 1 << (csiphy->data_lanes[i] + 11);
 #else
        for (i = 0; i < csiphy->num_data_lanes; i++)
-               reg |= 1 << i | 1 << (i + 12); 
+               reg |= 1 << i | 1 << (i + 12);
 #endif
 
        reg |= 1 << 4 | 1 << 16;
@@ -335,10 +333,14 @@ static int csi2rx_start(struct stf_csi_dev *csi_dev)
        return 0;
 }
 
-static void csi2rx_stop(void *reg_base)
+static void csi2rx_stop(struct stf_csi_dev *csi_dev, void *reg_base)
 {
+    struct stf_vin_dev *vin = csi_dev->stfcamss->vin;
        unsigned int i;
 
+    reg_assert_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE, BIT(2)|BIT(3));
+
        for (i = 0; i < CSI2RX_STREAMS_MAX; i++)
                writel(0, reg_base + CSI2RX_STREAM_CTRL_REG(i));
 }
@@ -355,10 +357,33 @@ static int stf_csi_stream_set(struct stf_csi_dev *csi_dev, int on)
        else
                return 0;
 
+    switch (csi_dev->s_type) {
+    case SENSOR_VIN:
+       st_err(ST_CSI, "please check csi_dev s_type:%d\n", csi_dev->s_type);
+               break;
+    case SENSOR_ISP0:
+        reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
+                       BIT(7)|BIT(6),
+                       0<<6);        
+               reg_set_bit(vin->sysctrl_base,  SYSCONSAIF_SYSCFG_36,
+                       BIT(11)|BIT(10)|BIT(9)|BIT(8),
+                       0<<8);
+        reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
+                       BIT(12), 0<<12);
+        reg_set_bit(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36,
+                       BIT(16)|BIT(15)|BIT(14)|BIT(13),
+                       0<<13);
+    case SENSOR_ISP1:
+       st_err(ST_CSI, "please check csi_dev s_type:%d\n", csi_dev->s_type);
+               break;
+    default:
+               break;
+    }
+
        if (on)
-               csi2rx_start(csi_dev);
+               csi2rx_start(csi_dev, reg_base);
        else
-               csi2rx_stop(reg_base);
+               csi2rx_stop(csi_dev, reg_base);
 
        return 0;
 }
index 7a544f3..79245ef 100755 (executable)
@@ -18,6 +18,20 @@ static int stf_csiphy_clk_set(struct stf_csiphy_dev *csiphy_dev, int on)
        }
        mutex_lock(&count_lock);
        if (on) {
+        reg_set_bit(vin->rstgen_base,
+            M31DPHY_APBCFGSAIF__SYSCFG_188,
+            BIT(6), BIT(6));
+//need to check one or two mipi input
+#ifdef USE_CSIDPHY_ONE_CLK_MODE        //one mipi input
+        reg_set_bit(vin->rstgen_base,
+            M31DPHY_APBCFGSAIF__SYSCFG_188,
+            BIT(7), BIT(7));
+#else                                                  //two mipi input
+        reg_set_bit(vin->rstgen_base,
+            M31DPHY_APBCFGSAIF__SYSCFG_188,
+            BIT(7), 0x2<<7);
+#endif
+#if 0
                if (count == 0) {
                        reg_set_bit(vin->clkgen_base,
                                CLK_DPHY_CFGCLK_ISPCORE_2X_CTRL,
@@ -40,11 +54,13 @@ static int stf_csiphy_clk_set(struct stf_csiphy_dev *csiphy_dev, int on)
                                CLK_DPHY_TXCLKESC_IN_CTRL,
                                1 << 31, 1 << 31);
                }
+#endif
                count++;
        } else {
                if (count == 0)
                        goto exit;
                if (count == 1) {
+#if 0
                        reg_set_bit(vin->clkgen_base,
                                CLK_DPHY_CFGCLK_ISPCORE_2X_CTRL,
                                1 << 31, 0 << 31);
@@ -56,6 +72,7 @@ static int stf_csiphy_clk_set(struct stf_csiphy_dev *csiphy_dev, int on)
                        reg_set_bit(vin->clkgen_base,
                                CLK_DPHY_TXCLKESC_IN_CTRL,
                                1 << 31, 0 << 31);
+#endif
                }
                count--;
        }
@@ -175,6 +192,79 @@ static int csi2rx_dphy_config(struct stf_vin_dev *vin,
 
        id = cfg->num_clks == 2 ? 1 : 0;
 
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(0), 0<<0);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(1), 0<<1);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(2), 0<<2);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(3), 0<<3);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(4), 0<<4);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(5), 0<<5);
+
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(8), 1<<8);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(9), 1<<9);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(10), 1<<10);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(11), 1<<11);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(17)|BIT(16)|BIT(15)|BIT(14)|BIT(13)|BIT(12),
+        0<<12);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(18), 0<<18);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(19), 0<<19);
+
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(22)|BIT(21)|BIT(20), cfg->clock_lane<<20);          //clock lane 0
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(25)|BIT(24)|BIT(23), cfg->clock1_lane<<23);         //clock lane 1
+
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(28)|BIT(27)|BIT(26), cfg->data_lanes[0]<<26);       //data lane 0
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_188,
+        BIT(31)|BIT(30)|BIT(29), cfg->data_lanes[1]<<29);       //data lane 1
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_192,
+        BIT(2)|BIT(1)|BIT(0), cfg->data_lanes[2]<<0);           //data lane 2
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_192,
+        BIT(5)|BIT(4)|BIT(3), cfg->data_lanes[3]<<3);           //data lane 3
+
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_192,
+        BIT(6), 0<<6);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_192,
+        BIT(11)|BIT(10)|BIT(9)|BIT(8)|BIT(7), 0<<7);
+    reg_set_bit(vin->rstgen_base,
+        M31DPHY_APBCFGSAIF__SYSCFG_200,
+        BIT(8), 0<<8);
+
+#if 0
        reg = reg_read(vin->sysctrl_base, SYSCTRL_REG4);
 
        st_debug(ST_CSIPHY, "id = %d, clock_lane = %d, SYSCTRL_REG4: 0x%x\n",
@@ -208,7 +298,7 @@ static int csi2rx_dphy_config(struct stf_vin_dev *vin,
 
        print_reg(ST_CSIPHY, vin->sysctrl_base, SYSCTRL_REG4);
        print_reg(ST_CSIPHY, vin->sysctrl_base, SYSCTRL_DPHY_CTRL);
-
+#endif
        return 0;
 }
 
index dc4bfba..94db134 100755 (executable)
@@ -59,6 +59,50 @@ static const regval_t isp_sc2235_reg_config_list[] = {
        {0x00000000, 0x00000001, 0, 0},
 };
 
+static const regval_t isp_ov13850_reg_config_list[] = {
+       {0x00000014, 0x00000001, 0, 0},
+//     {0x00000018, 0x000011BB, 0, 0},
+       {0x00000A1C, 0x00000030, 0, 0},
+//     {0x0000001C, 0x00000000, 0, 0},
+//     {0x00000020, 0x0437077F, 0, 0},
+//     {0x00000A0C, 0x04380780, 0, 0},
+       {0x00000A80, 0x88000000, 0, 0},
+       {0x00000A84, 0x881fa400, 0, 0},
+//     {0x00000A88, 0x00000780, 0, 0},
+       {0x00000A8C, 0x00000010, 0, 0},
+       {0x00000A90, 0x00000000, 0, 0},
+       {0x00000A94, 0x803f4810, 0, 0},
+       {0x00000A98, 0x80517990, 0, 0},
+       {0x00000A9c, 0x000005c0, 0, 0},
+       {0x00000AA0, 0x0c000000, 0, 0},
+       {0x00000AA4, 0x0c000000, 0, 0},
+       {0x00000AA8, 0x05a0032a, 0, 0},
+       {0x00000AAC, 0x0418e410, 0, 0},
+       {0x00000AB0, 0x0420cd10, 0, 0},
+       {0x00000AB4, 0x0000021c, 0, 0},
+       {0x00000AB8, 0x08000000, 0, 0},
+       {0x00000ABc, 0x08000000, 0, 0},
+       {0x00000AC0, 0x021c03c0, 0, 0},
+       {0x00000AC4, 0x00000000, 0, 0},
+       {0x00000E40, 0x0000004D, 0, 0},
+       {0x00000E44, 0x00000096, 0, 0},
+       {0x00000E48, 0x0000001D, 0, 0},
+       {0x00000E4C, 0x000001DA, 0, 0},
+       {0x00000E50, 0x000001B6, 0, 0},
+       {0x00000E54, 0x00000070, 0, 0},
+       {0x00000E58, 0x0000009D, 0, 0},
+       {0x00000E5C, 0x0000017C, 0, 0},
+       {0x00000E60, 0x000001E6, 0, 0},
+       {0x00000010, 0x00000000, 0, 0},
+    {0x00000A08, 0x10000022, 0xFFFFFFF, 0},
+       {0x00000044, 0x00000000, 0, 0},
+       {0x00000008, 0x00010005, 0, 0},
+       {0x00000A00, 0x00120002, 0, 0},
+       {0x00000A00, 0x00120000, 0, 0},
+       {0x00000A00, 0x00120001, 0, 0},
+       {0x00000000, 0x00000001, 0, 0},
+};
+
 static const regval_t isp_1080p_reg_config_list[] = {
        {0x00000014, 0x0000000D, 0, 0},
        // {0x00000018, 0x000011BB, 0, 0},
@@ -140,6 +184,11 @@ const struct reg_table isp_sc2235_settings[] = {
        ARRAY_SIZE(isp_sc2235_reg_config_list)},
 };
 
+const struct reg_table isp_ov13850_settings[] = {
+       {isp_ov13850_reg_config_list,
+       ARRAY_SIZE(isp_ov13850_reg_config_list)},
+};
+
 static regval_t isp_format_reg_list[] = {
        {0x0000001C, 0x00000000, 0, 0},
        {0x00000020, 0x0437077F, 0, 0},
@@ -273,6 +322,7 @@ static int stf_isp_set_format(struct stf_isp_dev *isp_dev,
        if (isp_dev->id == 0) {
                ispbase = vin->isp_isp0_base;
                isp_settings = isp_sc2235_settings;
+               //isp_settings = isp_ov13850_settings;
        } else {
                ispbase = vin->isp_isp1_base;
                isp_settings = isp_sc2235_settings;
index 5e23f38..62ac5a3 100755 (executable)
@@ -110,25 +110,47 @@ static int stf_vin_clk_enable(struct stf_vin2_dev *vin_dev)
        reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PCLK, CLK_U0_VIN_PCLK_ICG, 0x1<<31);
        reg_set_bit(vin->clkgen_base, CLK_U0_VIN_SYS_CLK, CLK_MUX_SEL, 0x2);
        reg_set_bit(vin->clkgen_base, CLK_U0_ISPV2_TOP_WRAPPER_CLK_C, CLK_U0_ISPV2_CLK_ICG, 0x1<<31);
-       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET, 
+       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
                SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE,
                RST_U0_ISPV2_TOP_WRAPPER_RST_P);
        reg_set_bit(vin->clkgen_base, CLK_U0_ISPV2_TOP_WRAPPER_CLK_C, CLK_U0_ISPV2_MUX_SEL, 0x0);
-       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET, 
+       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
                SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE,
                RST_U0_ISPV2_TOP_WRAPPER_RST_C);
        reg_set_bit(vin->clkgen_base, CLK_DVP_INV, CLK_POLARITY, 0x0);
        reg_set_bit(vin->clkgen_base, CLK_U0_ISPV2_TOP_WRAPPER_CLK_C, CLK_U0_ISPV2_MUX_SEL, 0x1<<24);
-       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET, 
+       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
                SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE,
-               RSTN_U0_VIN_RST_N_PCLK 
-               | RSTN_U0_VIN_RST_P_AXIRD 
+               RSTN_U0_VIN_RST_N_PCLK
+               | RSTN_U0_VIN_RST_P_AXIRD
                | RSTN_U0_VIN_RST_N_SYS_CLK);
        reg_set_bit(vin->clkgen_base,   CLK_U0_VIN_CLK_P_AXIWR, CLK_U0_VIN_MUX_SEL, 0x0);
-       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET, 
-               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE, RSTN_U0_VIN_RST_P_AXIWR);       
+       reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE, RSTN_U0_VIN_RST_P_AXIWR);
        reg_set_bit(vin->clkgen_base,   CLK_U0_VIN_CLK_P_AXIWR, CLK_U0_VIN_MUX_SEL, 0x1<<24);
 
+#if 0
+    //disable first, need to check mipi config on EVB
+    reg_set_bit(vin->clkgen_base, CLK_MIPI_RX0_PXL, BIT(3)|BIT(2)|BIT(1)|BIT(0), 0x3<<0);
+    reg_set_bit(vin->clkgen_base, CLK_U0_ISPV2_TOP_WRAPPER_CLK_C, BIT(24), 0x0<<24);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF0, BIT(31), 0x1<<31);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF1, BIT(31), 0x1<<31);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF2, BIT(31), 0x1<<31);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF3, BIT(31), 0x1<<31);
+
+
+    reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE,
+        BIT(4)|BIT(9));
+
+    reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE,
+        BIT(5)|BIT(6)|BIT(7)|BIT(8)|BIT(10));
+
+    reg_set_bit(vin->clkgen_base,      CLK_U0_VIN_CLK_P_AXIWR, BIT(24), 0x0<<24);
+    reg_clear_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE, BIT(11));
+#endif
        return 0;
 }
 
@@ -139,12 +161,27 @@ static int stf_vin_clk_disable(struct stf_vin2_dev *vin_dev)
        struct stf_vin_dev *vin = vin_dev->stfcamss->vin;
 
        reg_assert_rst(vin->clkgen_base,SOFTWARE_RESET_ASSERT0_ASSERT_SET,
-               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE, RSTN_U0_VIN_RST_N_PCLK 
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE, RSTN_U0_VIN_RST_N_PCLK
                | RSTN_U0_VIN_RST_N_SYS_CLK
                | RSTN_U0_VIN_RST_P_AXIRD
-               | RSTN_U0_VIN_RST_P_AXIWR);   
+               | RSTN_U0_VIN_RST_P_AXIWR);
+
        reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PCLK, CLK_U0_VIN_PCLK_ICG, 0x0);
 
+#if 0
+    //disable first, need to check mipi config on EVB
+    reg_assert_rst(vin->clkgen_base, SOFTWARE_RESET_ASSERT0_ASSERT_SET,
+               SOFTWARE_RESET_ASSERT0_ASSERT_SET_STATE,
+        BIT(6)|BIT(7)|BIT(8));
+
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PCLK, BIT(31), 0x0<<31);
+
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF0, BIT(31), 0x0<<31);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF1, BIT(31), 0x0<<31);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF2, BIT(31), 0x0<<31);
+    reg_set_bit(vin->clkgen_base, CLK_U0_VIN_PIXEL_CLK_IF3, BIT(31), 0x0<<31);
+#endif
+
        return 0;
 }
 
@@ -214,11 +251,11 @@ static void stf_vin_power_on(struct stf_vin2_dev *vin_dev,        int enable)
                reg_write(vin->pmu_test, SW_ENCOURAGE, 0xff);
                reg_write(vin->pmu_test, SW_ENCOURAGE, 0x05);
                reg_write(vin->pmu_test, SW_ENCOURAGE, 0x50);
-               
+
                reg_set_highest_bit(vin->sys_crg, 0xCCU);
                reg_set_highest_bit(vin->sys_crg, 0xD0U);
                reg_clear_rst(vin->sys_crg, 0x2FCU,0x30CU, (0x1 << 9));
-               reg_clear_rst(vin->sys_crg, 0x2FCU,0x30CU, (0x1 << 10));        
+               reg_clear_rst(vin->sys_crg, 0x2FCU,0x30CU, (0x1 << 10));
        } else {
                reg = reg_read(vin->sysctrl_base, SYSCONSAIF_SYSCFG_36);
                if(reg && U0_VIN_CNFG_ISP_DVP_EN0) {
@@ -227,6 +264,7 @@ static void stf_vin_power_on(struct stf_vin2_dev *vin_dev,  int enable)
                        reg_set_bit(vin->sys_crg, 0xccu, BIT(31), 0x0);
                        reg_set_bit(vin->sys_crg, 0xd0u, BIT(31), 0x0);
                        reg_write(vin->pmu_test, SW_DEST_POWER_ON, (0x1<<5));
+                       //reg_write(vin->pmu_test, SW_DEST_POWER_OFF, (0x1<<5));        //changhuang modify 01-12
                        reg_write(vin->pmu_test, SW_ENCOURAGE, 0xff);
                        reg_write(vin->pmu_test, SW_ENCOURAGE, 0x0a);
                        reg_write(vin->pmu_test, SW_ENCOURAGE, 0xa0);
@@ -234,8 +272,6 @@ static void stf_vin_power_on(struct stf_vin2_dev *vin_dev,  int enable)
        }
 }
 
-
-
 static void stf_vin_wr_rd_set_addr(struct stf_vin2_dev *vin_dev,
                dma_addr_t wr_addr, dma_addr_t rd_addr)
 {
@@ -326,7 +362,6 @@ void dump_vin_reg(void *__iomem regbase)
 }
 
 struct vin_hw_ops vin_ops = {
-       
        .vin_clk_init          = stf_vin_clk_init,
        .vin_clk_enable        = stf_vin_clk_enable,
        .vin_clk_disable       = stf_vin_clk_disable,
@@ -341,4 +376,5 @@ struct vin_hw_ops vin_ops = {
        .vin_isp_set_raw_addr  = stf_vin_isp_set_raw_addr,
        .vin_wr_irq_handler    = stf_vin_wr_irq_handler,
        .vin_isp_irq_handler   = stf_vin_isp_irq_handler,
+
 };
index 405cfc6..3a1209d 100755 (executable)
@@ -70,6 +70,8 @@
 #define CLK_DOM4_APB_FUNC                      0x0
 #define CLK_MUX_SEL                                    0xffffff
 
+#define CLK_MIPI_RX0_PXL            0x4
+
 #define CLK_DVP_INV                                    0x8
 #define CLK_U0_VIN_PCLK                                0x18
 #define CLK_U0_VIN_PCLK_ICG                                            (0x1<<31)
 #define CLK_U0_VIN_CLK_P_AXIWR                 0x30
 #define CLK_U0_VIN_MUX_SEL                     (BIT(24) | BIT(25) | BIT(26) | BIT(27) | BIT(28) | BIT(29))
 
+#define CLK_U0_VIN_PIXEL_CLK_IF0    0x20
+#define CLK_U0_VIN_PIXEL_CLK_IF1    0x24
+#define CLK_U0_VIN_PIXEL_CLK_IF2    0x28
+#define CLK_U0_VIN_PIXEL_CLK_IF3    0x2c
+
+#define CLK_U0_VIN_CLK_P_AXIWR      0x30
+
 #define CLK_U0_ISPV2_TOP_WRAPPER_CLK_C 0x34u
 #define CLK_U0_ISPV2_MUX_SEL           (0x1<<24 | 0x1<<25 | 0x1<<26 | 0x1<<27 | 0x1<<28 | 0x1<< 29)
 
 
 
 
-
+//pmu registers
 #define SW_DEST_POWER_ON                       0x0C
+#define SW_DEST_POWER_OFF                      0x10
 #define SW_ENCOURAGE                           0x44
 
 
 #define STREAM0_FCC_CTRL        0x124
 #define STREAM0_FIFO_FILL_LVL   0x128
 
+//m31_dphy registers
+#define M31DPHY_APBCFGSAIF__SYSCFG_188      0xbc
+#define M31DPHY_APBCFGSAIF__SYSCFG_192      0xc0
+#define M31DPHY_APBCFGSAIF__SYSCFG_196      0xc4
+#define M31DPHY_APBCFGSAIF__SYSCFG_200      0xc8
+
 typedef enum
 {
     DT_RAW6  = 0x28,