--- /dev/null
+// 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