13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * ov13855 camera driver
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (C) 2021 Rockchip Electronics Co., Ltd.
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * V0.0X01.0X00 first version.
83d0407baSopenharmony_ci * V0.0X01.0X01 fix some errors.
93d0407baSopenharmony_ci * V0.0X01.0X02 add get_selection.
103d0407baSopenharmony_ci *
113d0407baSopenharmony_ci */
123d0407baSopenharmony_ci
133d0407baSopenharmony_ci#include <linux/clk.h>
143d0407baSopenharmony_ci#include <linux/device.h>
153d0407baSopenharmony_ci#include <linux/delay.h>
163d0407baSopenharmony_ci#include <linux/gpio/consumer.h>
173d0407baSopenharmony_ci#include <linux/i2c.h>
183d0407baSopenharmony_ci#include <linux/module.h>
193d0407baSopenharmony_ci#include <linux/pm_runtime.h>
203d0407baSopenharmony_ci#include <linux/regulator/consumer.h>
213d0407baSopenharmony_ci#include <linux/sysfs.h>
223d0407baSopenharmony_ci#include <linux/slab.h>
233d0407baSopenharmony_ci#include <linux/version.h>
243d0407baSopenharmony_ci#include <linux/compat.h>
253d0407baSopenharmony_ci#include <linux/rk-camera-module.h>
263d0407baSopenharmony_ci#include <media/media-entity.h>
273d0407baSopenharmony_ci#include <media/v4l2-async.h>
283d0407baSopenharmony_ci#include <media/v4l2-ctrls.h>
293d0407baSopenharmony_ci#include <media/v4l2-subdev.h>
303d0407baSopenharmony_ci#include <linux/pinctrl/consumer.h>
313d0407baSopenharmony_ci
323d0407baSopenharmony_ci#define DRIVER_VERSION			KERNEL_VERSION(0, 0x01, 0x02)
333d0407baSopenharmony_ci
343d0407baSopenharmony_ci#ifndef V4L2_CID_DIGITAL_GAIN
353d0407baSopenharmony_ci#define V4L2_CID_DIGITAL_GAIN		V4L2_CID_GAIN
363d0407baSopenharmony_ci#endif
373d0407baSopenharmony_ci
383d0407baSopenharmony_ci#define OV13855_LINK_FREQ_540MHZ	540000000U
393d0407baSopenharmony_ci#define OV13855_LINK_FREQ_270MHZ	270000000U
403d0407baSopenharmony_ci/* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */
413d0407baSopenharmony_ci#define OV13855_PIXEL_RATE		(OV13855_LINK_FREQ_540MHZ * 2LL * 4LL / 10LL)
423d0407baSopenharmony_ci#define OV13855_XVCLK_FREQ		24000000
433d0407baSopenharmony_ci
443d0407baSopenharmony_ci#define CHIP_ID				0x00d855
453d0407baSopenharmony_ci#define OV13855_REG_CHIP_ID		0x300a
463d0407baSopenharmony_ci
473d0407baSopenharmony_ci#define OV13855_REG_CTRL_MODE		0x0100
483d0407baSopenharmony_ci#define OV13855_MODE_SW_STANDBY		0x0
493d0407baSopenharmony_ci#define OV13855_MODE_STREAMING		BIT(0)
503d0407baSopenharmony_ci
513d0407baSopenharmony_ci#define OV13855_REG_EXPOSURE		0x3500
523d0407baSopenharmony_ci#define	OV13855_EXPOSURE_MIN		4
533d0407baSopenharmony_ci#define	OV13855_EXPOSURE_STEP		1
543d0407baSopenharmony_ci#define OV13855_VTS_MAX			0x7fff
553d0407baSopenharmony_ci
563d0407baSopenharmony_ci#define OV13855_REG_GAIN_H		0x3508
573d0407baSopenharmony_ci#define OV13855_REG_GAIN_L		0x3509
583d0407baSopenharmony_ci#define OV13855_GAIN_H_MASK		0x1f
593d0407baSopenharmony_ci#define OV13855_GAIN_H_SHIFT		8
603d0407baSopenharmony_ci#define OV13855_GAIN_L_MASK		0xff
613d0407baSopenharmony_ci#define OV13855_GAIN_MIN		0x80
623d0407baSopenharmony_ci#define OV13855_GAIN_MAX		0x7c0
633d0407baSopenharmony_ci#define OV13855_GAIN_STEP		1
643d0407baSopenharmony_ci#define OV13855_GAIN_DEFAULT		0x80
653d0407baSopenharmony_ci
663d0407baSopenharmony_ci#define OV13855_REG_TEST_PATTERN	0x5e00
673d0407baSopenharmony_ci#define	OV13855_TEST_PATTERN_ENABLE	0x80
683d0407baSopenharmony_ci#define	OV13855_TEST_PATTERN_DISABLE	0x0
693d0407baSopenharmony_ci
703d0407baSopenharmony_ci#define OV13855_REG_VTS			0x380e
713d0407baSopenharmony_ci
723d0407baSopenharmony_ci#define REG_NULL			0xFFFF
733d0407baSopenharmony_ci
743d0407baSopenharmony_ci#define OV13855_REG_VALUE_08BIT		1
753d0407baSopenharmony_ci#define OV13855_REG_VALUE_16BIT		2
763d0407baSopenharmony_ci#define OV13855_REG_VALUE_24BIT		3
773d0407baSopenharmony_ci
783d0407baSopenharmony_ci#define OV13855_LANES			4
793d0407baSopenharmony_ci#define OV13855_BITS_PER_SAMPLE		10
803d0407baSopenharmony_ci
813d0407baSopenharmony_ci#define OV13855_CHIP_REVISION_REG	0x302A
823d0407baSopenharmony_ci
833d0407baSopenharmony_ci#define OF_CAMERA_PINCTRL_STATE_DEFAULT	"rockchip,camera_default"
843d0407baSopenharmony_ci#define OF_CAMERA_PINCTRL_STATE_SLEEP	"rockchip,camera_sleep"
853d0407baSopenharmony_ci
863d0407baSopenharmony_ci#define OV13855_NAME			"ov13855"
873d0407baSopenharmony_ci#define OV13855_MEDIA_BUS_FMT		MEDIA_BUS_FMT_SBGGR10_1X10
883d0407baSopenharmony_ci
893d0407baSopenharmony_cistatic const char * const ov13855_supply_names[] = {
903d0407baSopenharmony_ci	"avdd",		/* Analog power */
913d0407baSopenharmony_ci	"dovdd",	/* Digital I/O power */
923d0407baSopenharmony_ci	"dvdd",		/* Digital core power */
933d0407baSopenharmony_ci};
943d0407baSopenharmony_ci
953d0407baSopenharmony_ci#define OV13855_NUM_SUPPLIES ARRAY_SIZE(ov13855_supply_names)
963d0407baSopenharmony_ci
973d0407baSopenharmony_cistruct regval {
983d0407baSopenharmony_ci	u16 addr;
993d0407baSopenharmony_ci	u8 val;
1003d0407baSopenharmony_ci};
1013d0407baSopenharmony_ci
1023d0407baSopenharmony_cistruct ov13855_mode {
1033d0407baSopenharmony_ci	u32 width;
1043d0407baSopenharmony_ci	u32 height;
1053d0407baSopenharmony_ci	struct v4l2_fract max_fps;
1063d0407baSopenharmony_ci	u32 hts_def;
1073d0407baSopenharmony_ci	u32 vts_def;
1083d0407baSopenharmony_ci	u32 exp_def;
1093d0407baSopenharmony_ci	u32 link_freq_idx;
1103d0407baSopenharmony_ci	u32 bpp;
1113d0407baSopenharmony_ci	const struct regval *reg_list;
1123d0407baSopenharmony_ci};
1133d0407baSopenharmony_ci
1143d0407baSopenharmony_cistruct ov13855 {
1153d0407baSopenharmony_ci	struct i2c_client	*client;
1163d0407baSopenharmony_ci	struct clk		*xvclk;
1173d0407baSopenharmony_ci	struct gpio_desc	*power_gpio;
1183d0407baSopenharmony_ci	struct gpio_desc	*reset_gpio;
1193d0407baSopenharmony_ci	struct gpio_desc	*pwdn_gpio;
1203d0407baSopenharmony_ci	struct regulator_bulk_data supplies[OV13855_NUM_SUPPLIES];
1213d0407baSopenharmony_ci
1223d0407baSopenharmony_ci	struct pinctrl		*pinctrl;
1233d0407baSopenharmony_ci	struct pinctrl_state	*pins_default;
1243d0407baSopenharmony_ci	struct pinctrl_state	*pins_sleep;
1253d0407baSopenharmony_ci
1263d0407baSopenharmony_ci	struct v4l2_subdev	subdev;
1273d0407baSopenharmony_ci	struct media_pad	pad;
1283d0407baSopenharmony_ci	struct v4l2_ctrl_handler ctrl_handler;
1293d0407baSopenharmony_ci	struct v4l2_ctrl	*exposure;
1303d0407baSopenharmony_ci	struct v4l2_ctrl	*anal_gain;
1313d0407baSopenharmony_ci	struct v4l2_ctrl	*digi_gain;
1323d0407baSopenharmony_ci	struct v4l2_ctrl	*hblank;
1333d0407baSopenharmony_ci	struct v4l2_ctrl	*vblank;
1343d0407baSopenharmony_ci	struct v4l2_ctrl	*pixel_rate;
1353d0407baSopenharmony_ci	struct v4l2_ctrl	*link_freq;
1363d0407baSopenharmony_ci	struct v4l2_ctrl	*test_pattern;
1373d0407baSopenharmony_ci	struct mutex		mutex;
1383d0407baSopenharmony_ci	bool			streaming;
1393d0407baSopenharmony_ci	bool			power_on;
1403d0407baSopenharmony_ci	const struct ov13855_mode *cur_mode;
1413d0407baSopenharmony_ci	u32			module_index;
1423d0407baSopenharmony_ci	const char		*module_facing;
1433d0407baSopenharmony_ci	const char		*module_name;
1443d0407baSopenharmony_ci	const char		*len_name;
1453d0407baSopenharmony_ci};
1463d0407baSopenharmony_ci
1473d0407baSopenharmony_ci#define to_ov13855(sd) container_of(sd, struct ov13855, subdev)
1483d0407baSopenharmony_ci
1493d0407baSopenharmony_ci/*
1503d0407baSopenharmony_ci * Xclk 24Mhz
1513d0407baSopenharmony_ci */
1523d0407baSopenharmony_cistatic const struct regval ov13855_global_regs[] = {
1533d0407baSopenharmony_ci	{0x0103, 0x01},
1543d0407baSopenharmony_ci	{0x0300, 0x02},
1553d0407baSopenharmony_ci	{0x0301, 0x00},
1563d0407baSopenharmony_ci	{0x0302, 0x5a},
1573d0407baSopenharmony_ci	{0x0303, 0x00},
1583d0407baSopenharmony_ci	{0x0304, 0x00},
1593d0407baSopenharmony_ci	{0x0305, 0x01},
1603d0407baSopenharmony_ci	{0x030b, 0x06},
1613d0407baSopenharmony_ci	{0x030c, 0x02},
1623d0407baSopenharmony_ci	{0x030d, 0x88},
1633d0407baSopenharmony_ci	{0x0312, 0x11},
1643d0407baSopenharmony_ci	{0x3022, 0x01},
1653d0407baSopenharmony_ci	{0x3013, 0x32},
1663d0407baSopenharmony_ci	{0x3016, 0x72},
1673d0407baSopenharmony_ci	{0x301b, 0xF0},
1683d0407baSopenharmony_ci	{0x301f, 0xd0},
1693d0407baSopenharmony_ci	{0x3106, 0x15},
1703d0407baSopenharmony_ci	{0x3107, 0x23},
1713d0407baSopenharmony_ci	{0x3500, 0x00},
1723d0407baSopenharmony_ci	{0x3501, 0x80},
1733d0407baSopenharmony_ci	{0x3502, 0x00},
1743d0407baSopenharmony_ci	{0x3508, 0x02},
1753d0407baSopenharmony_ci	{0x3509, 0x00},
1763d0407baSopenharmony_ci	{0x350a, 0x00},
1773d0407baSopenharmony_ci	{0x350e, 0x00},
1783d0407baSopenharmony_ci	{0x3510, 0x00},
1793d0407baSopenharmony_ci	{0x3511, 0x02},
1803d0407baSopenharmony_ci	{0x3512, 0x00},
1813d0407baSopenharmony_ci	{0x3600, 0x2b},
1823d0407baSopenharmony_ci	{0x3601, 0x52},
1833d0407baSopenharmony_ci	{0x3602, 0x60},
1843d0407baSopenharmony_ci	{0x3612, 0x05},
1853d0407baSopenharmony_ci	{0x3613, 0xa4},
1863d0407baSopenharmony_ci	{0x3620, 0x80},
1873d0407baSopenharmony_ci	{0x3621, 0x10},
1883d0407baSopenharmony_ci	{0x3622, 0x30},
1893d0407baSopenharmony_ci	{0x3624, 0x1c},
1903d0407baSopenharmony_ci	{0x3640, 0x10},
1913d0407baSopenharmony_ci	{0x3661, 0x70},
1923d0407baSopenharmony_ci	{0x3661, 0x80},
1933d0407baSopenharmony_ci	{0x3662, 0x12},
1943d0407baSopenharmony_ci	{0x3664, 0x73},
1953d0407baSopenharmony_ci	{0x3665, 0xa7},
1963d0407baSopenharmony_ci	{0x366e, 0xff},
1973d0407baSopenharmony_ci	{0x366f, 0xf4},
1983d0407baSopenharmony_ci	{0x3674, 0x00},
1993d0407baSopenharmony_ci	{0x3679, 0x0c},
2003d0407baSopenharmony_ci	{0x367f, 0x01},
2013d0407baSopenharmony_ci	{0x3680, 0x0c},
2023d0407baSopenharmony_ci	{0x3681, 0x50},
2033d0407baSopenharmony_ci	{0x3682, 0x50},
2043d0407baSopenharmony_ci	{0x3683, 0xa9},
2053d0407baSopenharmony_ci	{0x3684, 0xa9},
2063d0407baSopenharmony_ci	{0x3709, 0x5f},
2073d0407baSopenharmony_ci	{0x3714, 0x24},
2083d0407baSopenharmony_ci	{0x371a, 0x3e},
2093d0407baSopenharmony_ci	{0x3737, 0x04},
2103d0407baSopenharmony_ci	{0x3738, 0xcc},
2113d0407baSopenharmony_ci	{0x3739, 0x12},
2123d0407baSopenharmony_ci	{0x373d, 0x26},
2133d0407baSopenharmony_ci	{0x3764, 0x20},
2143d0407baSopenharmony_ci	{0x3765, 0x20},
2153d0407baSopenharmony_ci	{0x37a1, 0x36},
2163d0407baSopenharmony_ci	{0x37a8, 0x3b},
2173d0407baSopenharmony_ci	{0x37ab, 0x31},
2183d0407baSopenharmony_ci	{0x37c2, 0x04},
2193d0407baSopenharmony_ci	{0x37c3, 0xf1},
2203d0407baSopenharmony_ci	{0x37c5, 0x00},
2213d0407baSopenharmony_ci	{0x37d8, 0x03},
2223d0407baSopenharmony_ci	{0x37d9, 0x0c},
2233d0407baSopenharmony_ci	{0x37da, 0xc2},
2243d0407baSopenharmony_ci	{0x37dc, 0x02},
2253d0407baSopenharmony_ci	{0x37e0, 0x00},
2263d0407baSopenharmony_ci	{0x37e1, 0x0a},
2273d0407baSopenharmony_ci	{0x37e2, 0x14},
2283d0407baSopenharmony_ci	{0x37e3, 0x04},
2293d0407baSopenharmony_ci	{0x37e4, 0x2a},
2303d0407baSopenharmony_ci	{0x37e5, 0x03},
2313d0407baSopenharmony_ci	{0x37e6, 0x04},
2323d0407baSopenharmony_ci	{0x3800, 0x00},
2333d0407baSopenharmony_ci	{0x3801, 0x00},
2343d0407baSopenharmony_ci	{0x3802, 0x00},
2353d0407baSopenharmony_ci	{0x3803, 0x08},
2363d0407baSopenharmony_ci	{0x3804, 0x10},
2373d0407baSopenharmony_ci	{0x3805, 0x9f},
2383d0407baSopenharmony_ci	{0x3806, 0x0c},
2393d0407baSopenharmony_ci	{0x3807, 0x57},
2403d0407baSopenharmony_ci	{0x3808, 0x10},
2413d0407baSopenharmony_ci	{0x3809, 0x80},
2423d0407baSopenharmony_ci	{0x380a, 0x0c},
2433d0407baSopenharmony_ci	{0x380b, 0x40},
2443d0407baSopenharmony_ci	{0x380c, 0x04},
2453d0407baSopenharmony_ci	{0x380d, 0x62},
2463d0407baSopenharmony_ci	{0x380e, 0x0c},
2473d0407baSopenharmony_ci	{0x380f, 0x8e},
2483d0407baSopenharmony_ci	{0x3811, 0x10},
2493d0407baSopenharmony_ci	{0x3813, 0x08},
2503d0407baSopenharmony_ci	{0x3814, 0x01},
2513d0407baSopenharmony_ci	{0x3815, 0x01},
2523d0407baSopenharmony_ci	{0x3816, 0x01},
2533d0407baSopenharmony_ci	{0x3817, 0x01},
2543d0407baSopenharmony_ci	{0x3820, 0xa8},
2553d0407baSopenharmony_ci	{0x3821, 0x00},
2563d0407baSopenharmony_ci	{0x3822, 0xc2},
2573d0407baSopenharmony_ci	{0x3823, 0x18},
2583d0407baSopenharmony_ci	{0x3826, 0x11},
2593d0407baSopenharmony_ci	{0x3827, 0x1c},
2603d0407baSopenharmony_ci	{0x3829, 0x03},
2613d0407baSopenharmony_ci	{0x3832, 0x00},
2623d0407baSopenharmony_ci	{0x3c80, 0x00},
2633d0407baSopenharmony_ci	{0x3c87, 0x01},
2643d0407baSopenharmony_ci	{0x3c8c, 0x19},
2653d0407baSopenharmony_ci	{0x3c8d, 0x1c},
2663d0407baSopenharmony_ci	{0x3c90, 0x00},
2673d0407baSopenharmony_ci	{0x3c91, 0x00},
2683d0407baSopenharmony_ci	{0x3c92, 0x00},
2693d0407baSopenharmony_ci	{0x3c93, 0x00},
2703d0407baSopenharmony_ci	{0x3c94, 0x40},
2713d0407baSopenharmony_ci	{0x3c95, 0x54},
2723d0407baSopenharmony_ci	{0x3c96, 0x34},
2733d0407baSopenharmony_ci	{0x3c97, 0x04},
2743d0407baSopenharmony_ci	{0x3c98, 0x00},
2753d0407baSopenharmony_ci	{0x3d8c, 0x73},
2763d0407baSopenharmony_ci	{0x3d8d, 0xc0},
2773d0407baSopenharmony_ci	{0x3f00, 0x0b},
2783d0407baSopenharmony_ci	{0x3f03, 0x00},
2793d0407baSopenharmony_ci	{0x4001, 0xe0},
2803d0407baSopenharmony_ci	{0x4008, 0x00},
2813d0407baSopenharmony_ci	{0x4009, 0x0f},
2823d0407baSopenharmony_ci	{0x4011, 0xf0},
2833d0407baSopenharmony_ci	{0x4050, 0x04},
2843d0407baSopenharmony_ci	{0x4051, 0x0b},
2853d0407baSopenharmony_ci	{0x4052, 0x00},
2863d0407baSopenharmony_ci	{0x4053, 0x80},
2873d0407baSopenharmony_ci	{0x4054, 0x00},
2883d0407baSopenharmony_ci	{0x4055, 0x80},
2893d0407baSopenharmony_ci	{0x4056, 0x00},
2903d0407baSopenharmony_ci	{0x4057, 0x80},
2913d0407baSopenharmony_ci	{0x4058, 0x00},
2923d0407baSopenharmony_ci	{0x4059, 0x80},
2933d0407baSopenharmony_ci	{0x405e, 0x00},
2943d0407baSopenharmony_ci	{0x4500, 0x07},
2953d0407baSopenharmony_ci	{0x4503, 0x00},
2963d0407baSopenharmony_ci	{0x450a, 0x04},
2973d0407baSopenharmony_ci	{0x4809, 0x04},
2983d0407baSopenharmony_ci	{0x480c, 0x12},
2993d0407baSopenharmony_ci	{0x481f, 0x30},
3003d0407baSopenharmony_ci	{0x4833, 0x10},
3013d0407baSopenharmony_ci	{0x4837, 0x0e},
3023d0407baSopenharmony_ci	{0x4902, 0x01},
3033d0407baSopenharmony_ci	{0x4d00, 0x03},
3043d0407baSopenharmony_ci	{0x4d01, 0xc9},
3053d0407baSopenharmony_ci	{0x4d02, 0xbc},
3063d0407baSopenharmony_ci	{0x4d03, 0xd7},
3073d0407baSopenharmony_ci	{0x4d04, 0xf0},
3083d0407baSopenharmony_ci	{0x4d05, 0xa2},
3093d0407baSopenharmony_ci	{0x5000, 0xff},
3103d0407baSopenharmony_ci	{0x5001, 0x07},
3113d0407baSopenharmony_ci	{0x5040, 0x39},
3123d0407baSopenharmony_ci	{0x5041, 0x10},
3133d0407baSopenharmony_ci	{0x5042, 0x10},
3143d0407baSopenharmony_ci	{0x5043, 0x84},
3153d0407baSopenharmony_ci	{0x5044, 0x62},
3163d0407baSopenharmony_ci	{0x5180, 0x00},
3173d0407baSopenharmony_ci	{0x5181, 0x10},
3183d0407baSopenharmony_ci	{0x5182, 0x02},
3193d0407baSopenharmony_ci	{0x5183, 0x0f},
3203d0407baSopenharmony_ci	{0x5200, 0x1b},
3213d0407baSopenharmony_ci	{0x520b, 0x07},
3223d0407baSopenharmony_ci	{0x520c, 0x0f},
3233d0407baSopenharmony_ci	{0x5300, 0x04},
3243d0407baSopenharmony_ci	{0x5301, 0x0C},
3253d0407baSopenharmony_ci	{0x5302, 0x0C},
3263d0407baSopenharmony_ci	{0x5303, 0x0f},
3273d0407baSopenharmony_ci	{0x5304, 0x00},
3283d0407baSopenharmony_ci	{0x5305, 0x70},
3293d0407baSopenharmony_ci	{0x5306, 0x00},
3303d0407baSopenharmony_ci	{0x5307, 0x80},
3313d0407baSopenharmony_ci	{0x5308, 0x00},
3323d0407baSopenharmony_ci	{0x5309, 0xa5},
3333d0407baSopenharmony_ci	{0x530a, 0x00},
3343d0407baSopenharmony_ci	{0x530b, 0xd3},
3353d0407baSopenharmony_ci	{0x530c, 0x00},
3363d0407baSopenharmony_ci	{0x530d, 0xf0},
3373d0407baSopenharmony_ci	{0x530e, 0x01},
3383d0407baSopenharmony_ci	{0x530f, 0x10},
3393d0407baSopenharmony_ci	{0x5310, 0x01},
3403d0407baSopenharmony_ci	{0x5311, 0x20},
3413d0407baSopenharmony_ci	{0x5312, 0x01},
3423d0407baSopenharmony_ci	{0x5313, 0x20},
3433d0407baSopenharmony_ci	{0x5314, 0x01},
3443d0407baSopenharmony_ci	{0x5315, 0x20},
3453d0407baSopenharmony_ci	{0x5316, 0x08},
3463d0407baSopenharmony_ci	{0x5317, 0x08},
3473d0407baSopenharmony_ci	{0x5318, 0x10},
3483d0407baSopenharmony_ci	{0x5319, 0x88},
3493d0407baSopenharmony_ci	{0x531a, 0x88},
3503d0407baSopenharmony_ci	{0x531b, 0xa9},
3513d0407baSopenharmony_ci	{0x531c, 0xaa},
3523d0407baSopenharmony_ci	{0x531d, 0x0a},
3533d0407baSopenharmony_ci	{0x5405, 0x02},
3543d0407baSopenharmony_ci	{0x5406, 0x67},
3553d0407baSopenharmony_ci	{0x5407, 0x01},
3563d0407baSopenharmony_ci	{0x5408, 0x4a},
3573d0407baSopenharmony_ci	{REG_NULL, 0x00},
3583d0407baSopenharmony_ci};
3593d0407baSopenharmony_ci
3603d0407baSopenharmony_ci/*
3613d0407baSopenharmony_ci * Xclk 24Mhz
3623d0407baSopenharmony_ci * max_framerate 30fps
3633d0407baSopenharmony_ci * mipi_datarate per lane 540Mbps
3643d0407baSopenharmony_ci */
3653d0407baSopenharmony_cistatic const struct regval ov13855_2112x1568_30fps_regs[] = {
3663d0407baSopenharmony_ci	{0x0103, 0x01},
3673d0407baSopenharmony_ci	{0x0300, 0x02},
3683d0407baSopenharmony_ci	{0x0301, 0x00},
3693d0407baSopenharmony_ci	{0x0302, 0x5a},
3703d0407baSopenharmony_ci	{0x0303, 0x01},
3713d0407baSopenharmony_ci	{0x0304, 0x00},
3723d0407baSopenharmony_ci	{0x0305, 0x01},
3733d0407baSopenharmony_ci	{0x3022, 0x01},
3743d0407baSopenharmony_ci	{0x3013, 0x32},
3753d0407baSopenharmony_ci	{0x3016, 0x72},
3763d0407baSopenharmony_ci	{0x301b, 0xF0},
3773d0407baSopenharmony_ci	{0x301f, 0xd0},
3783d0407baSopenharmony_ci	{0x3106, 0x15},
3793d0407baSopenharmony_ci	{0x3107, 0x23},
3803d0407baSopenharmony_ci	{0x3500, 0x00},
3813d0407baSopenharmony_ci	{0x3501, 0x40},
3823d0407baSopenharmony_ci	{0x3502, 0x00},
3833d0407baSopenharmony_ci	{0x3508, 0x02},
3843d0407baSopenharmony_ci	{0x3509, 0x00},
3853d0407baSopenharmony_ci	{0x350a, 0x00},
3863d0407baSopenharmony_ci	{0x350e, 0x00},
3873d0407baSopenharmony_ci	{0x3510, 0x00},
3883d0407baSopenharmony_ci	{0x3511, 0x02},
3893d0407baSopenharmony_ci	{0x3512, 0x00},
3903d0407baSopenharmony_ci	{0x3600, 0x2b},
3913d0407baSopenharmony_ci	{0x3601, 0x52},
3923d0407baSopenharmony_ci	{0x3602, 0x60},
3933d0407baSopenharmony_ci	{0x3612, 0x05},
3943d0407baSopenharmony_ci	{0x3613, 0xa4},
3953d0407baSopenharmony_ci	{0x3620, 0x80},
3963d0407baSopenharmony_ci	{0x3621, 0x08},
3973d0407baSopenharmony_ci	{0x3622, 0x30},
3983d0407baSopenharmony_ci	{0x3624, 0x1c},
3993d0407baSopenharmony_ci	{0x3640, 0x08},
4003d0407baSopenharmony_ci	{0x3641, 0x70},
4013d0407baSopenharmony_ci	{0x3661, 0x80},
4023d0407baSopenharmony_ci	{0x3662, 0x10},
4033d0407baSopenharmony_ci	{0x3664, 0x73},
4043d0407baSopenharmony_ci	{0x3665, 0xa7},
4053d0407baSopenharmony_ci	{0x366e, 0xff},
4063d0407baSopenharmony_ci	{0x366f, 0xf4},
4073d0407baSopenharmony_ci	{0x3674, 0x00},
4083d0407baSopenharmony_ci	{0x3679, 0x0c},
4093d0407baSopenharmony_ci	{0x367f, 0x01},
4103d0407baSopenharmony_ci	{0x3680, 0x0c},
4113d0407baSopenharmony_ci	{0x3681, 0x60},
4123d0407baSopenharmony_ci	{0x3682, 0x17},
4133d0407baSopenharmony_ci	{0x3683, 0xa9},
4143d0407baSopenharmony_ci	{0x3684, 0x9a},
4153d0407baSopenharmony_ci	{0x3709, 0x68},
4163d0407baSopenharmony_ci	{0x3714, 0x28},
4173d0407baSopenharmony_ci	{0x371a, 0x3e},
4183d0407baSopenharmony_ci	{0x3737, 0x08},
4193d0407baSopenharmony_ci	{0x3738, 0xcc},
4203d0407baSopenharmony_ci	{0x3739, 0x20},
4213d0407baSopenharmony_ci	{0x373d, 0x26},
4223d0407baSopenharmony_ci	{0x3764, 0x20},
4233d0407baSopenharmony_ci	{0x3765, 0x20},
4243d0407baSopenharmony_ci	{0x37a1, 0x36},
4253d0407baSopenharmony_ci	{0x37a8, 0x3b},
4263d0407baSopenharmony_ci	{0x37ab, 0x31},
4273d0407baSopenharmony_ci	{0x37c2, 0x14},
4283d0407baSopenharmony_ci	{0x37c3, 0xf1},
4293d0407baSopenharmony_ci	{0x37c5, 0x00},
4303d0407baSopenharmony_ci	{0x37d8, 0x03},
4313d0407baSopenharmony_ci	{0x37d9, 0x0c},
4323d0407baSopenharmony_ci	{0x37da, 0xc2},
4333d0407baSopenharmony_ci	{0x37dc, 0x02},
4343d0407baSopenharmony_ci	{0x37e0, 0x00},
4353d0407baSopenharmony_ci	{0x37e1, 0x0a},
4363d0407baSopenharmony_ci	{0x37e2, 0x14},
4373d0407baSopenharmony_ci	{0x37e3, 0x08},
4383d0407baSopenharmony_ci	{0x37e4, 0x38},
4393d0407baSopenharmony_ci	{0x37e5, 0x03},
4403d0407baSopenharmony_ci	{0x37e6, 0x08},
4413d0407baSopenharmony_ci	{0x3800, 0x00},
4423d0407baSopenharmony_ci	{0x3801, 0x00},
4433d0407baSopenharmony_ci	{0x3802, 0x00},
4443d0407baSopenharmony_ci	{0x3803, 0x08},
4453d0407baSopenharmony_ci	{0x3804, 0x10},
4463d0407baSopenharmony_ci	{0x3805, 0x9f},
4473d0407baSopenharmony_ci	{0x3806, 0x0c},
4483d0407baSopenharmony_ci	{0x3807, 0x4f},
4493d0407baSopenharmony_ci	{0x3808, 0x08},
4503d0407baSopenharmony_ci	{0x3809, 0x40},
4513d0407baSopenharmony_ci	{0x380a, 0x06},
4523d0407baSopenharmony_ci	{0x380b, 0x20},
4533d0407baSopenharmony_ci	{0x380c, 0x08},
4543d0407baSopenharmony_ci	{0x380d, 0xc4},
4553d0407baSopenharmony_ci	{0x380e, 0x06},
4563d0407baSopenharmony_ci	{0x380f, 0x48},
4573d0407baSopenharmony_ci	{0x3811, 0x08},
4583d0407baSopenharmony_ci	{0x3813, 0x02},
4593d0407baSopenharmony_ci	{0x3814, 0x03},
4603d0407baSopenharmony_ci	{0x3815, 0x01},
4613d0407baSopenharmony_ci	{0x3816, 0x03},
4623d0407baSopenharmony_ci	{0x3817, 0x01},
4633d0407baSopenharmony_ci	{0x3820, 0xab},
4643d0407baSopenharmony_ci	{0x3821, 0x00},
4653d0407baSopenharmony_ci	{0x3822, 0xc2},
4663d0407baSopenharmony_ci	{0x3823, 0x18},
4673d0407baSopenharmony_ci	{0x3826, 0x04},
4683d0407baSopenharmony_ci	{0x3827, 0x90},
4693d0407baSopenharmony_ci	{0x3829, 0x07},
4703d0407baSopenharmony_ci	{0x3832, 0x00},
4713d0407baSopenharmony_ci	{0x3c80, 0x00},
4723d0407baSopenharmony_ci	{0x3c87, 0x01},
4733d0407baSopenharmony_ci	{0x3c8c, 0x19},
4743d0407baSopenharmony_ci	{0x3c8d, 0x1c},
4753d0407baSopenharmony_ci	{0x3c90, 0x00},
4763d0407baSopenharmony_ci	{0x3c91, 0x00},
4773d0407baSopenharmony_ci	{0x3c92, 0x00},
4783d0407baSopenharmony_ci	{0x3c93, 0x00},
4793d0407baSopenharmony_ci	{0x3c94, 0x40},
4803d0407baSopenharmony_ci	{0x3c95, 0x54},
4813d0407baSopenharmony_ci	{0x3c96, 0x34},
4823d0407baSopenharmony_ci	{0x3c97, 0x04},
4833d0407baSopenharmony_ci	{0x3c98, 0x00},
4843d0407baSopenharmony_ci	{0x3d8c, 0x73},
4853d0407baSopenharmony_ci	{0x3d8d, 0xc0},
4863d0407baSopenharmony_ci	{0x3f00, 0x0b},
4873d0407baSopenharmony_ci	{0x3f03, 0x00},
4883d0407baSopenharmony_ci	{0x4001, 0xe0},
4893d0407baSopenharmony_ci	{0x4008, 0x00},
4903d0407baSopenharmony_ci	{0x4009, 0x0d},
4913d0407baSopenharmony_ci	{0x4011, 0xf0},
4923d0407baSopenharmony_ci	{0x4017, 0x08},
4933d0407baSopenharmony_ci	{0x4050, 0x04},
4943d0407baSopenharmony_ci	{0x4051, 0x0b},
4953d0407baSopenharmony_ci	{0x4052, 0x00},
4963d0407baSopenharmony_ci	{0x4053, 0x80},
4973d0407baSopenharmony_ci	{0x4054, 0x00},
4983d0407baSopenharmony_ci	{0x4055, 0x80},
4993d0407baSopenharmony_ci	{0x4056, 0x00},
5003d0407baSopenharmony_ci	{0x4057, 0x80},
5013d0407baSopenharmony_ci	{0x4058, 0x00},
5023d0407baSopenharmony_ci	{0x4059, 0x80},
5033d0407baSopenharmony_ci	{0x405e, 0x20},
5043d0407baSopenharmony_ci	{0x4500, 0x07},
5053d0407baSopenharmony_ci	{0x4503, 0x00},
5063d0407baSopenharmony_ci	{0x450a, 0x04},
5073d0407baSopenharmony_ci	{0x4809, 0x04},
5083d0407baSopenharmony_ci	{0x480c, 0x12},
5093d0407baSopenharmony_ci	{0x481f, 0x30},
5103d0407baSopenharmony_ci	{0x4833, 0x10},
5113d0407baSopenharmony_ci	{0x4837, 0x1c},
5123d0407baSopenharmony_ci	{0x4902, 0x01},
5133d0407baSopenharmony_ci	{0x4d00, 0x03},
5143d0407baSopenharmony_ci	{0x4d01, 0xc9},
5153d0407baSopenharmony_ci	{0x4d02, 0xbc},
5163d0407baSopenharmony_ci	{0x4d03, 0xd7},
5173d0407baSopenharmony_ci	{0x4d04, 0xf0},
5183d0407baSopenharmony_ci	{0x4d05, 0xa2},
5193d0407baSopenharmony_ci	{0x5000, 0xfd},
5203d0407baSopenharmony_ci	{0x5001, 0x01},
5213d0407baSopenharmony_ci	{0x5040, 0x39},
5223d0407baSopenharmony_ci	{0x5041, 0x10},
5233d0407baSopenharmony_ci	{0x5042, 0x10},
5243d0407baSopenharmony_ci	{0x5043, 0x84},
5253d0407baSopenharmony_ci	{0x5044, 0x62},
5263d0407baSopenharmony_ci	{0x5180, 0x00},
5273d0407baSopenharmony_ci	{0x5181, 0x10},
5283d0407baSopenharmony_ci	{0x5182, 0x02},
5293d0407baSopenharmony_ci	{0x5183, 0x0f},
5303d0407baSopenharmony_ci	{0x5200, 0x1b},
5313d0407baSopenharmony_ci	{0x520b, 0x07},
5323d0407baSopenharmony_ci	{0x520c, 0x0f},
5333d0407baSopenharmony_ci	{0x5300, 0x04},
5343d0407baSopenharmony_ci	{0x5301, 0x0C},
5353d0407baSopenharmony_ci	{0x5302, 0x0C},
5363d0407baSopenharmony_ci	{0x5303, 0x0f},
5373d0407baSopenharmony_ci	{0x5304, 0x00},
5383d0407baSopenharmony_ci	{0x5305, 0x70},
5393d0407baSopenharmony_ci	{0x5306, 0x00},
5403d0407baSopenharmony_ci	{0x5307, 0x80},
5413d0407baSopenharmony_ci	{0x5308, 0x00},
5423d0407baSopenharmony_ci	{0x5309, 0xa5},
5433d0407baSopenharmony_ci	{0x530a, 0x00},
5443d0407baSopenharmony_ci	{0x530b, 0xd3},
5453d0407baSopenharmony_ci	{0x530c, 0x00},
5463d0407baSopenharmony_ci	{0x530d, 0xf0},
5473d0407baSopenharmony_ci	{0x530e, 0x01},
5483d0407baSopenharmony_ci	{0x530f, 0x10},
5493d0407baSopenharmony_ci	{0x5310, 0x01},
5503d0407baSopenharmony_ci	{0x5311, 0x20},
5513d0407baSopenharmony_ci	{0x5312, 0x01},
5523d0407baSopenharmony_ci	{0x5313, 0x20},
5533d0407baSopenharmony_ci	{0x5314, 0x01},
5543d0407baSopenharmony_ci	{0x5315, 0x20},
5553d0407baSopenharmony_ci	{0x5316, 0x08},
5563d0407baSopenharmony_ci	{0x5317, 0x08},
5573d0407baSopenharmony_ci	{0x5318, 0x10},
5583d0407baSopenharmony_ci	{0x5319, 0x88},
5593d0407baSopenharmony_ci	{0x531a, 0x88},
5603d0407baSopenharmony_ci	{0x531b, 0xa9},
5613d0407baSopenharmony_ci	{0x531c, 0xaa},
5623d0407baSopenharmony_ci	{0x531d, 0x0a},
5633d0407baSopenharmony_ci	{0x5405, 0x02},
5643d0407baSopenharmony_ci	{0x5406, 0x67},
5653d0407baSopenharmony_ci	{0x5407, 0x01},
5663d0407baSopenharmony_ci	{0x5408, 0x4a},
5673d0407baSopenharmony_ci	{0x0100, 0x01},
5683d0407baSopenharmony_ci	{REG_NULL, 0x00},
5693d0407baSopenharmony_ci};
5703d0407baSopenharmony_ci
5713d0407baSopenharmony_ci/*
5723d0407baSopenharmony_ci * Xclk 24Mhz
5733d0407baSopenharmony_ci * max_framerate 30fps
5743d0407baSopenharmony_ci * mipi_datarate per lane 1080Mbps
5753d0407baSopenharmony_ci */
5763d0407baSopenharmony_cistatic const struct regval ov13855_4224x3136_30fps_regs[] = {
5773d0407baSopenharmony_ci	{0x0103, 0x01},
5783d0407baSopenharmony_ci	{0x0300, 0x02},
5793d0407baSopenharmony_ci	{0x0301, 0x00},
5803d0407baSopenharmony_ci	{0x0302, 0x5a},
5813d0407baSopenharmony_ci	{0x0303, 0x00},
5823d0407baSopenharmony_ci	{0x0304, 0x00},
5833d0407baSopenharmony_ci	{0x0305, 0x01},
5843d0407baSopenharmony_ci	{0x030b, 0x06},
5853d0407baSopenharmony_ci	{0x030c, 0x02},
5863d0407baSopenharmony_ci	{0x030d, 0x88},
5873d0407baSopenharmony_ci	{0x0312, 0x11},
5883d0407baSopenharmony_ci	{0x3022, 0x01},
5893d0407baSopenharmony_ci	{0x3012, 0x40},
5903d0407baSopenharmony_ci	{0x3013, 0x72},
5913d0407baSopenharmony_ci	{0x3016, 0x72},
5923d0407baSopenharmony_ci	{0x301b, 0xF0},
5933d0407baSopenharmony_ci	{0x301f, 0xd0},
5943d0407baSopenharmony_ci	{0x3106, 0x15},
5953d0407baSopenharmony_ci	{0x3107, 0x23},
5963d0407baSopenharmony_ci	{0x3500, 0x00},
5973d0407baSopenharmony_ci	{0x3501, 0x80},
5983d0407baSopenharmony_ci	{0x3502, 0x00},
5993d0407baSopenharmony_ci	{0x3508, 0x02},
6003d0407baSopenharmony_ci	{0x3509, 0x00},
6013d0407baSopenharmony_ci	{0x350a, 0x00},
6023d0407baSopenharmony_ci	{0x350e, 0x00},
6033d0407baSopenharmony_ci	{0x3510, 0x00},
6043d0407baSopenharmony_ci	{0x3511, 0x02},
6053d0407baSopenharmony_ci	{0x3512, 0x00},
6063d0407baSopenharmony_ci	{0x3600, 0x2b},
6073d0407baSopenharmony_ci	{0x3601, 0x52},
6083d0407baSopenharmony_ci	{0x3602, 0x60},
6093d0407baSopenharmony_ci	{0x3612, 0x05},
6103d0407baSopenharmony_ci	{0x3613, 0xa4},
6113d0407baSopenharmony_ci	{0x3620, 0x80},
6123d0407baSopenharmony_ci	{0x3621, 0x10},
6133d0407baSopenharmony_ci	{0x3622, 0x30},
6143d0407baSopenharmony_ci	{0x3624, 0x1c},
6153d0407baSopenharmony_ci	{0x3640, 0x10},
6163d0407baSopenharmony_ci	{0x3641, 0x70},
6173d0407baSopenharmony_ci	{0x3660, 0x04},
6183d0407baSopenharmony_ci	{0x3661, 0x80},
6193d0407baSopenharmony_ci	{0x3662, 0x12},
6203d0407baSopenharmony_ci	{0x3664, 0x73},
6213d0407baSopenharmony_ci	{0x3665, 0xa7},
6223d0407baSopenharmony_ci	{0x366e, 0xff},
6233d0407baSopenharmony_ci	{0x366f, 0xf4},
6243d0407baSopenharmony_ci	{0x3674, 0x00},
6253d0407baSopenharmony_ci	{0x3679, 0x0c},
6263d0407baSopenharmony_ci	{0x367f, 0x01},
6273d0407baSopenharmony_ci	{0x3680, 0x0c},
6283d0407baSopenharmony_ci	{0x3681, 0x50},
6293d0407baSopenharmony_ci	{0x3682, 0x50},
6303d0407baSopenharmony_ci	{0x3683, 0xa9},
6313d0407baSopenharmony_ci	{0x3684, 0xa9},
6323d0407baSopenharmony_ci	{0x3706, 0x40},
6333d0407baSopenharmony_ci	{0x3709, 0x5f},
6343d0407baSopenharmony_ci	{0x3714, 0x24},
6353d0407baSopenharmony_ci	{0x371a, 0x3e},
6363d0407baSopenharmony_ci	{0x3737, 0x04},
6373d0407baSopenharmony_ci	{0x3738, 0xcc},
6383d0407baSopenharmony_ci	{0x3739, 0x12},
6393d0407baSopenharmony_ci	{0x373d, 0x26},
6403d0407baSopenharmony_ci	{0x3764, 0x20},
6413d0407baSopenharmony_ci	{0x3765, 0x20},
6423d0407baSopenharmony_ci	{0x37a1, 0x36},
6433d0407baSopenharmony_ci	{0x37a8, 0x3b},
6443d0407baSopenharmony_ci	{0x37ab, 0x31},
6453d0407baSopenharmony_ci	{0x37c2, 0x04},
6463d0407baSopenharmony_ci	{0x37c3, 0xf1},
6473d0407baSopenharmony_ci	{0x37c5, 0x00},
6483d0407baSopenharmony_ci	{0x37d8, 0x03},
6493d0407baSopenharmony_ci	{0x37d9, 0x0c},
6503d0407baSopenharmony_ci	{0x37da, 0xc2},
6513d0407baSopenharmony_ci	{0x37dc, 0x02},
6523d0407baSopenharmony_ci	{0x37e0, 0x00},
6533d0407baSopenharmony_ci	{0x37e1, 0x0a},
6543d0407baSopenharmony_ci	{0x37e2, 0x14},
6553d0407baSopenharmony_ci	{0x37e3, 0x04},
6563d0407baSopenharmony_ci	{0x37e4, 0x2A},
6573d0407baSopenharmony_ci	{0x37e5, 0x03},
6583d0407baSopenharmony_ci	{0x37e6, 0x04},
6593d0407baSopenharmony_ci	{0x3800, 0x00},
6603d0407baSopenharmony_ci	{0x3801, 0x00},
6613d0407baSopenharmony_ci	{0x3802, 0x00},
6623d0407baSopenharmony_ci	{0x3803, 0x08},
6633d0407baSopenharmony_ci	{0x3804, 0x10},
6643d0407baSopenharmony_ci	{0x3805, 0x9f},
6653d0407baSopenharmony_ci	{0x3806, 0x0c},
6663d0407baSopenharmony_ci	{0x3807, 0x57},
6673d0407baSopenharmony_ci	{0x3808, 0x10},
6683d0407baSopenharmony_ci	{0x3809, 0x80},
6693d0407baSopenharmony_ci	{0x380a, 0x0c},
6703d0407baSopenharmony_ci	{0x380b, 0x40},
6713d0407baSopenharmony_ci	{0x380c, 0x04},
6723d0407baSopenharmony_ci	{0x380d, 0x62},
6733d0407baSopenharmony_ci	{0x380e, 0x0c},
6743d0407baSopenharmony_ci	{0x380f, 0x8e},
6753d0407baSopenharmony_ci	{0x3811, 0x10},
6763d0407baSopenharmony_ci	{0x3813, 0x08},
6773d0407baSopenharmony_ci	{0x3814, 0x01},
6783d0407baSopenharmony_ci	{0x3815, 0x01},
6793d0407baSopenharmony_ci	{0x3816, 0x01},
6803d0407baSopenharmony_ci	{0x3817, 0x01},
6813d0407baSopenharmony_ci	{0x3820, 0xa8},
6823d0407baSopenharmony_ci	{0x3821, 0x00},
6833d0407baSopenharmony_ci	{0x3822, 0xd2},
6843d0407baSopenharmony_ci	{0x3823, 0x18},
6853d0407baSopenharmony_ci	{0x3826, 0x11},
6863d0407baSopenharmony_ci	{0x3827, 0x1c},
6873d0407baSopenharmony_ci	{0x3829, 0x03},
6883d0407baSopenharmony_ci	{0x3832, 0x00},
6893d0407baSopenharmony_ci	{0x3c80, 0x00},
6903d0407baSopenharmony_ci	{0x3c87, 0x01},
6913d0407baSopenharmony_ci	{0x3c8c, 0x19},
6923d0407baSopenharmony_ci	{0x3c8d, 0x1c},
6933d0407baSopenharmony_ci	{0x3c90, 0x00},
6943d0407baSopenharmony_ci	{0x3c91, 0x00},
6953d0407baSopenharmony_ci	{0x3c92, 0x00},
6963d0407baSopenharmony_ci	{0x3c93, 0x00},
6973d0407baSopenharmony_ci	{0x3c94, 0x40},
6983d0407baSopenharmony_ci	{0x3c95, 0x54},
6993d0407baSopenharmony_ci	{0x3c96, 0x34},
7003d0407baSopenharmony_ci	{0x3c97, 0x04},
7013d0407baSopenharmony_ci	{0x3c98, 0x00},
7023d0407baSopenharmony_ci	{0x3d8c, 0x73},
7033d0407baSopenharmony_ci	{0x3d8d, 0xc0},
7043d0407baSopenharmony_ci	{0x3f00, 0x0b},
7053d0407baSopenharmony_ci	{0x3f03, 0x00},
7063d0407baSopenharmony_ci	{0x4001, 0xe0},
7073d0407baSopenharmony_ci	{0x4008, 0x00},
7083d0407baSopenharmony_ci	{0x4009, 0x0f},
7093d0407baSopenharmony_ci	{0x4011, 0xf0},
7103d0407baSopenharmony_ci	{0x4017, 0x08},
7113d0407baSopenharmony_ci	{0x4050, 0x04},
7123d0407baSopenharmony_ci	{0x4051, 0x0b},
7133d0407baSopenharmony_ci	{0x4052, 0x00},
7143d0407baSopenharmony_ci	{0x4053, 0x80},
7153d0407baSopenharmony_ci	{0x4054, 0x00},
7163d0407baSopenharmony_ci	{0x4055, 0x80},
7173d0407baSopenharmony_ci	{0x4056, 0x00},
7183d0407baSopenharmony_ci	{0x4057, 0x80},
7193d0407baSopenharmony_ci	{0x4058, 0x00},
7203d0407baSopenharmony_ci	{0x4059, 0x80},
7213d0407baSopenharmony_ci	{0x405e, 0x00},
7223d0407baSopenharmony_ci	{0x4500, 0x07},
7233d0407baSopenharmony_ci	{0x4503, 0x00},
7243d0407baSopenharmony_ci	{0x450a, 0x04},
7253d0407baSopenharmony_ci	{0x4800, 0x60},
7263d0407baSopenharmony_ci	{0x4809, 0x04},
7273d0407baSopenharmony_ci	{0x480c, 0x12},
7283d0407baSopenharmony_ci	{0x481f, 0x30},
7293d0407baSopenharmony_ci	{0x4833, 0x10},
7303d0407baSopenharmony_ci	{0x4837, 0x0e},
7313d0407baSopenharmony_ci	{0x4902, 0x01},
7323d0407baSopenharmony_ci	{0x4d00, 0x03},
7333d0407baSopenharmony_ci	{0x4d01, 0xc9},
7343d0407baSopenharmony_ci	{0x4d02, 0xbc},
7353d0407baSopenharmony_ci	{0x4d03, 0xd7},
7363d0407baSopenharmony_ci	{0x4d04, 0xf0},
7373d0407baSopenharmony_ci	{0x4d05, 0xa2},
7383d0407baSopenharmony_ci	{0x5000, 0xff},
7393d0407baSopenharmony_ci	{0x5001, 0x07},
7403d0407baSopenharmony_ci	{0x5040, 0x39},
7413d0407baSopenharmony_ci	{0x5041, 0x10},
7423d0407baSopenharmony_ci	{0x5042, 0x10},
7433d0407baSopenharmony_ci	{0x5043, 0x84},
7443d0407baSopenharmony_ci	{0x5044, 0x62},
7453d0407baSopenharmony_ci	{0x5180, 0x00},
7463d0407baSopenharmony_ci	{0x5181, 0x10},
7473d0407baSopenharmony_ci	{0x5182, 0x02},
7483d0407baSopenharmony_ci	{0x5183, 0x0f},
7493d0407baSopenharmony_ci	{0x5200, 0x1b},
7503d0407baSopenharmony_ci	{0x520b, 0x07},
7513d0407baSopenharmony_ci	{0x520c, 0x0f},
7523d0407baSopenharmony_ci	{0x5300, 0x04},
7533d0407baSopenharmony_ci	{0x5301, 0x0C},
7543d0407baSopenharmony_ci	{0x5302, 0x0C},
7553d0407baSopenharmony_ci	{0x5303, 0x0f},
7563d0407baSopenharmony_ci	{0x5304, 0x00},
7573d0407baSopenharmony_ci	{0x5305, 0x70},
7583d0407baSopenharmony_ci	{0x5306, 0x00},
7593d0407baSopenharmony_ci	{0x5307, 0x80},
7603d0407baSopenharmony_ci	{0x5308, 0x00},
7613d0407baSopenharmony_ci	{0x5309, 0xa5},
7623d0407baSopenharmony_ci	{0x530a, 0x00},
7633d0407baSopenharmony_ci	{0x530b, 0xd3},
7643d0407baSopenharmony_ci	{0x530c, 0x00},
7653d0407baSopenharmony_ci	{0x530d, 0xf0},
7663d0407baSopenharmony_ci	{0x530e, 0x01},
7673d0407baSopenharmony_ci	{0x530f, 0x10},
7683d0407baSopenharmony_ci	{0x5310, 0x01},
7693d0407baSopenharmony_ci	{0x5311, 0x20},
7703d0407baSopenharmony_ci	{0x5312, 0x01},
7713d0407baSopenharmony_ci	{0x5313, 0x20},
7723d0407baSopenharmony_ci	{0x5314, 0x01},
7733d0407baSopenharmony_ci	{0x5315, 0x20},
7743d0407baSopenharmony_ci	{0x5316, 0x08},
7753d0407baSopenharmony_ci	{0x5317, 0x08},
7763d0407baSopenharmony_ci	{0x5318, 0x10},
7773d0407baSopenharmony_ci	{0x5319, 0x88},
7783d0407baSopenharmony_ci	{0x531a, 0x88},
7793d0407baSopenharmony_ci	{0x531b, 0xa9},
7803d0407baSopenharmony_ci	{0x531c, 0xaa},
7813d0407baSopenharmony_ci	{0x531d, 0x0a},
7823d0407baSopenharmony_ci	{0x5405, 0x02},
7833d0407baSopenharmony_ci	{0x5406, 0x67},
7843d0407baSopenharmony_ci	{0x5407, 0x01},
7853d0407baSopenharmony_ci	{0x5408, 0x4a},
7863d0407baSopenharmony_ci	{0x0100, 0x01},
7873d0407baSopenharmony_ci	{0x0100, 0x00},
7883d0407baSopenharmony_ci	{0x380c, 0x04},
7893d0407baSopenharmony_ci	{0x380d, 0x62},
7903d0407baSopenharmony_ci	{0x0303, 0x00},
7913d0407baSopenharmony_ci	{0x4837, 0x0e},
7923d0407baSopenharmony_ci	{0x0100, 0x01},
7933d0407baSopenharmony_ci	{REG_NULL, 0x00},
7943d0407baSopenharmony_ci};
7953d0407baSopenharmony_ci
7963d0407baSopenharmony_ci/*
7973d0407baSopenharmony_ci * Xclk 24Mhz
7983d0407baSopenharmony_ci * max_framerate 15fps
7993d0407baSopenharmony_ci * mipi_datarate per lane 1080Mbps
8003d0407baSopenharmony_ci */
8013d0407baSopenharmony_cistatic const struct regval ov13855_4224x3136_15fps_regs[] = {
8023d0407baSopenharmony_ci	{0x0103, 0x01},
8033d0407baSopenharmony_ci	{0x0300, 0x02},
8043d0407baSopenharmony_ci	{0x0301, 0x00},
8053d0407baSopenharmony_ci	{0x0302, 0x5a},
8063d0407baSopenharmony_ci	{0x0303, 0x00},
8073d0407baSopenharmony_ci	{0x0304, 0x00},
8083d0407baSopenharmony_ci	{0x0305, 0x01},
8093d0407baSopenharmony_ci	{0x030b, 0x06},
8103d0407baSopenharmony_ci	{0x030c, 0x02},
8113d0407baSopenharmony_ci	{0x030d, 0x88},
8123d0407baSopenharmony_ci	{0x0312, 0x11},
8133d0407baSopenharmony_ci	{0x3022, 0x01},
8143d0407baSopenharmony_ci	{0x3012, 0x40},
8153d0407baSopenharmony_ci	{0x3013, 0x72},
8163d0407baSopenharmony_ci	{0x3016, 0x72},
8173d0407baSopenharmony_ci	{0x301b, 0xF0},
8183d0407baSopenharmony_ci	{0x301f, 0xd0},
8193d0407baSopenharmony_ci	{0x3106, 0x15},
8203d0407baSopenharmony_ci	{0x3107, 0x23},
8213d0407baSopenharmony_ci	{0x3500, 0x00},
8223d0407baSopenharmony_ci	{0x3501, 0x80},
8233d0407baSopenharmony_ci	{0x3502, 0x00},
8243d0407baSopenharmony_ci	{0x3508, 0x02},
8253d0407baSopenharmony_ci	{0x3509, 0x00},
8263d0407baSopenharmony_ci	{0x350a, 0x00},
8273d0407baSopenharmony_ci	{0x350e, 0x00},
8283d0407baSopenharmony_ci	{0x3510, 0x00},
8293d0407baSopenharmony_ci	{0x3511, 0x02},
8303d0407baSopenharmony_ci	{0x3512, 0x00},
8313d0407baSopenharmony_ci	{0x3600, 0x2b},
8323d0407baSopenharmony_ci	{0x3601, 0x52},
8333d0407baSopenharmony_ci	{0x3602, 0x60},
8343d0407baSopenharmony_ci	{0x3612, 0x05},
8353d0407baSopenharmony_ci	{0x3613, 0xa4},
8363d0407baSopenharmony_ci	{0x3620, 0x80},
8373d0407baSopenharmony_ci	{0x3621, 0x10},
8383d0407baSopenharmony_ci	{0x3622, 0x30},
8393d0407baSopenharmony_ci	{0x3624, 0x1c},
8403d0407baSopenharmony_ci	{0x3640, 0x10},
8413d0407baSopenharmony_ci	{0x3641, 0x70},
8423d0407baSopenharmony_ci	{0x3660, 0x04},
8433d0407baSopenharmony_ci	{0x3661, 0x80},
8443d0407baSopenharmony_ci	{0x3662, 0x12},
8453d0407baSopenharmony_ci	{0x3664, 0x73},
8463d0407baSopenharmony_ci	{0x3665, 0xa7},
8473d0407baSopenharmony_ci	{0x366e, 0xff},
8483d0407baSopenharmony_ci	{0x366f, 0xf4},
8493d0407baSopenharmony_ci	{0x3674, 0x00},
8503d0407baSopenharmony_ci	{0x3679, 0x0c},
8513d0407baSopenharmony_ci	{0x367f, 0x01},
8523d0407baSopenharmony_ci	{0x3680, 0x0c},
8533d0407baSopenharmony_ci	{0x3681, 0x50},
8543d0407baSopenharmony_ci	{0x3682, 0x50},
8553d0407baSopenharmony_ci	{0x3683, 0xa9},
8563d0407baSopenharmony_ci	{0x3684, 0xa9},
8573d0407baSopenharmony_ci	{0x3706, 0x40},
8583d0407baSopenharmony_ci	{0x3709, 0x5f},
8593d0407baSopenharmony_ci	{0x3714, 0x24},
8603d0407baSopenharmony_ci	{0x371a, 0x3e},
8613d0407baSopenharmony_ci	{0x3737, 0x04},
8623d0407baSopenharmony_ci	{0x3738, 0xcc},
8633d0407baSopenharmony_ci	{0x3739, 0x12},
8643d0407baSopenharmony_ci	{0x373d, 0x26},
8653d0407baSopenharmony_ci	{0x3764, 0x20},
8663d0407baSopenharmony_ci	{0x3765, 0x20},
8673d0407baSopenharmony_ci	{0x37a1, 0x36},
8683d0407baSopenharmony_ci	{0x37a8, 0x3b},
8693d0407baSopenharmony_ci	{0x37ab, 0x31},
8703d0407baSopenharmony_ci	{0x37c2, 0x04},
8713d0407baSopenharmony_ci	{0x37c3, 0xf1},
8723d0407baSopenharmony_ci	{0x37c5, 0x00},
8733d0407baSopenharmony_ci	{0x37d8, 0x03},
8743d0407baSopenharmony_ci	{0x37d9, 0x0c},
8753d0407baSopenharmony_ci	{0x37da, 0xc2},
8763d0407baSopenharmony_ci	{0x37dc, 0x02},
8773d0407baSopenharmony_ci	{0x37e0, 0x00},
8783d0407baSopenharmony_ci	{0x37e1, 0x0a},
8793d0407baSopenharmony_ci	{0x37e2, 0x14},
8803d0407baSopenharmony_ci	{0x37e3, 0x04},
8813d0407baSopenharmony_ci	{0x37e4, 0x2A},
8823d0407baSopenharmony_ci	{0x37e5, 0x03},
8833d0407baSopenharmony_ci	{0x37e6, 0x04},
8843d0407baSopenharmony_ci	{0x3800, 0x00},
8853d0407baSopenharmony_ci	{0x3801, 0x00},
8863d0407baSopenharmony_ci	{0x3802, 0x00},
8873d0407baSopenharmony_ci	{0x3803, 0x08},
8883d0407baSopenharmony_ci	{0x3804, 0x10},
8893d0407baSopenharmony_ci	{0x3805, 0x9f},
8903d0407baSopenharmony_ci	{0x3806, 0x0c},
8913d0407baSopenharmony_ci	{0x3807, 0x57},
8923d0407baSopenharmony_ci	{0x3808, 0x10},
8933d0407baSopenharmony_ci	{0x3809, 0x80},
8943d0407baSopenharmony_ci	{0x380a, 0x0c},
8953d0407baSopenharmony_ci	{0x380b, 0x40},
8963d0407baSopenharmony_ci	{0x380c, 0x04},
8973d0407baSopenharmony_ci	{0x380d, 0x62},
8983d0407baSopenharmony_ci	{0x380e, 0x0c},
8993d0407baSopenharmony_ci	{0x380f, 0x8e},
9003d0407baSopenharmony_ci	{0x3811, 0x10},
9013d0407baSopenharmony_ci	{0x3813, 0x08},
9023d0407baSopenharmony_ci	{0x3814, 0x01},
9033d0407baSopenharmony_ci	{0x3815, 0x01},
9043d0407baSopenharmony_ci	{0x3816, 0x01},
9053d0407baSopenharmony_ci	{0x3817, 0x01},
9063d0407baSopenharmony_ci	{0x3820, 0xa8},
9073d0407baSopenharmony_ci	{0x3821, 0x00},
9083d0407baSopenharmony_ci	{0x3822, 0xd2},
9093d0407baSopenharmony_ci	{0x3823, 0x18},
9103d0407baSopenharmony_ci	{0x3826, 0x11},
9113d0407baSopenharmony_ci	{0x3827, 0x1c},
9123d0407baSopenharmony_ci	{0x3829, 0x03},
9133d0407baSopenharmony_ci	{0x3832, 0x00},
9143d0407baSopenharmony_ci	{0x3c80, 0x00},
9153d0407baSopenharmony_ci	{0x3c87, 0x01},
9163d0407baSopenharmony_ci	{0x3c8c, 0x19},
9173d0407baSopenharmony_ci	{0x3c8d, 0x1c},
9183d0407baSopenharmony_ci	{0x3c90, 0x00},
9193d0407baSopenharmony_ci	{0x3c91, 0x00},
9203d0407baSopenharmony_ci	{0x3c92, 0x00},
9213d0407baSopenharmony_ci	{0x3c93, 0x00},
9223d0407baSopenharmony_ci	{0x3c94, 0x40},
9233d0407baSopenharmony_ci	{0x3c95, 0x54},
9243d0407baSopenharmony_ci	{0x3c96, 0x34},
9253d0407baSopenharmony_ci	{0x3c97, 0x04},
9263d0407baSopenharmony_ci	{0x3c98, 0x00},
9273d0407baSopenharmony_ci	{0x3d8c, 0x73},
9283d0407baSopenharmony_ci	{0x3d8d, 0xc0},
9293d0407baSopenharmony_ci	{0x3f00, 0x0b},
9303d0407baSopenharmony_ci	{0x3f03, 0x00},
9313d0407baSopenharmony_ci	{0x4001, 0xe0},
9323d0407baSopenharmony_ci	{0x4008, 0x00},
9333d0407baSopenharmony_ci	{0x4009, 0x0f},
9343d0407baSopenharmony_ci	{0x4011, 0xf0},
9353d0407baSopenharmony_ci	{0x4017, 0x08},
9363d0407baSopenharmony_ci	{0x4050, 0x04},
9373d0407baSopenharmony_ci	{0x4051, 0x0b},
9383d0407baSopenharmony_ci	{0x4052, 0x00},
9393d0407baSopenharmony_ci	{0x4053, 0x80},
9403d0407baSopenharmony_ci	{0x4054, 0x00},
9413d0407baSopenharmony_ci	{0x4055, 0x80},
9423d0407baSopenharmony_ci	{0x4056, 0x00},
9433d0407baSopenharmony_ci	{0x4057, 0x80},
9443d0407baSopenharmony_ci	{0x4058, 0x00},
9453d0407baSopenharmony_ci	{0x4059, 0x80},
9463d0407baSopenharmony_ci	{0x405e, 0x00},
9473d0407baSopenharmony_ci	{0x4500, 0x07},
9483d0407baSopenharmony_ci	{0x4503, 0x00},
9493d0407baSopenharmony_ci	{0x450a, 0x04},
9503d0407baSopenharmony_ci	{0x4800, 0x60},
9513d0407baSopenharmony_ci	{0x4809, 0x04},
9523d0407baSopenharmony_ci	{0x480c, 0x12},
9533d0407baSopenharmony_ci	{0x481f, 0x30},
9543d0407baSopenharmony_ci	{0x4833, 0x10},
9553d0407baSopenharmony_ci	{0x4837, 0x0e},
9563d0407baSopenharmony_ci	{0x4902, 0x01},
9573d0407baSopenharmony_ci	{0x4d00, 0x03},
9583d0407baSopenharmony_ci	{0x4d01, 0xc9},
9593d0407baSopenharmony_ci	{0x4d02, 0xbc},
9603d0407baSopenharmony_ci	{0x4d03, 0xd7},
9613d0407baSopenharmony_ci	{0x4d04, 0xf0},
9623d0407baSopenharmony_ci	{0x4d05, 0xa2},
9633d0407baSopenharmony_ci	{0x5000, 0xff},
9643d0407baSopenharmony_ci	{0x5001, 0x07},
9653d0407baSopenharmony_ci	{0x5040, 0x39},
9663d0407baSopenharmony_ci	{0x5041, 0x10},
9673d0407baSopenharmony_ci	{0x5042, 0x10},
9683d0407baSopenharmony_ci	{0x5043, 0x84},
9693d0407baSopenharmony_ci	{0x5044, 0x62},
9703d0407baSopenharmony_ci	{0x5180, 0x00},
9713d0407baSopenharmony_ci	{0x5181, 0x10},
9723d0407baSopenharmony_ci	{0x5182, 0x02},
9733d0407baSopenharmony_ci	{0x5183, 0x0f},
9743d0407baSopenharmony_ci	{0x5200, 0x1b},
9753d0407baSopenharmony_ci	{0x520b, 0x07},
9763d0407baSopenharmony_ci	{0x520c, 0x0f},
9773d0407baSopenharmony_ci	{0x5300, 0x04},
9783d0407baSopenharmony_ci	{0x5301, 0x0C},
9793d0407baSopenharmony_ci	{0x5302, 0x0C},
9803d0407baSopenharmony_ci	{0x5303, 0x0f},
9813d0407baSopenharmony_ci	{0x5304, 0x00},
9823d0407baSopenharmony_ci	{0x5305, 0x70},
9833d0407baSopenharmony_ci	{0x5306, 0x00},
9843d0407baSopenharmony_ci	{0x5307, 0x80},
9853d0407baSopenharmony_ci	{0x5308, 0x00},
9863d0407baSopenharmony_ci	{0x5309, 0xa5},
9873d0407baSopenharmony_ci	{0x530a, 0x00},
9883d0407baSopenharmony_ci	{0x530b, 0xd3},
9893d0407baSopenharmony_ci	{0x530c, 0x00},
9903d0407baSopenharmony_ci	{0x530d, 0xf0},
9913d0407baSopenharmony_ci	{0x530e, 0x01},
9923d0407baSopenharmony_ci	{0x530f, 0x10},
9933d0407baSopenharmony_ci	{0x5310, 0x01},
9943d0407baSopenharmony_ci	{0x5311, 0x20},
9953d0407baSopenharmony_ci	{0x5312, 0x01},
9963d0407baSopenharmony_ci	{0x5313, 0x20},
9973d0407baSopenharmony_ci	{0x5314, 0x01},
9983d0407baSopenharmony_ci	{0x5315, 0x20},
9993d0407baSopenharmony_ci	{0x5316, 0x08},
10003d0407baSopenharmony_ci	{0x5317, 0x08},
10013d0407baSopenharmony_ci	{0x5318, 0x10},
10023d0407baSopenharmony_ci	{0x5319, 0x88},
10033d0407baSopenharmony_ci	{0x531a, 0x88},
10043d0407baSopenharmony_ci	{0x531b, 0xa9},
10053d0407baSopenharmony_ci	{0x531c, 0xaa},
10063d0407baSopenharmony_ci	{0x531d, 0x0a},
10073d0407baSopenharmony_ci	{0x5405, 0x02},
10083d0407baSopenharmony_ci	{0x5406, 0x67},
10093d0407baSopenharmony_ci	{0x5407, 0x01},
10103d0407baSopenharmony_ci	{0x5408, 0x4a},
10113d0407baSopenharmony_ci	{0x0100, 0x01},
10123d0407baSopenharmony_ci	{0x0100, 0x00},
10133d0407baSopenharmony_ci	{0x380c, 0x08},
10143d0407baSopenharmony_ci	{0x380d, 0xC4},
10153d0407baSopenharmony_ci	{0x0303, 0x01},
10163d0407baSopenharmony_ci	{0x4837, 0x1c},
10173d0407baSopenharmony_ci	{0x0100, 0x01},
10183d0407baSopenharmony_ci	{REG_NULL, 0x00},
10193d0407baSopenharmony_ci};
10203d0407baSopenharmony_ci
10213d0407baSopenharmony_cistatic const struct ov13855_mode supported_modes[] = {
10223d0407baSopenharmony_ci	{
10233d0407baSopenharmony_ci		.width = 4224,
10243d0407baSopenharmony_ci		.height = 3136,
10253d0407baSopenharmony_ci		.max_fps = {
10263d0407baSopenharmony_ci			.numerator = 10000,
10273d0407baSopenharmony_ci			.denominator = 300000,
10283d0407baSopenharmony_ci		},
10293d0407baSopenharmony_ci		.exp_def = 0x0c8a,
10303d0407baSopenharmony_ci		.hts_def = 0x0462,
10313d0407baSopenharmony_ci		.vts_def = 0x0c8e,
10323d0407baSopenharmony_ci		.bpp = 10,
10333d0407baSopenharmony_ci		.reg_list = ov13855_4224x3136_30fps_regs,
10343d0407baSopenharmony_ci		.link_freq_idx = 0,
10353d0407baSopenharmony_ci	},
10363d0407baSopenharmony_ci	{
10373d0407baSopenharmony_ci		.width = 4224,
10383d0407baSopenharmony_ci		.height = 3136,
10393d0407baSopenharmony_ci		.max_fps = {
10403d0407baSopenharmony_ci			.numerator = 10000,
10413d0407baSopenharmony_ci			.denominator = 150000,
10423d0407baSopenharmony_ci		},
10433d0407baSopenharmony_ci		.exp_def = 0x0c8a,
10443d0407baSopenharmony_ci		.hts_def = 0x0462,
10453d0407baSopenharmony_ci		.vts_def = 0x0c8e,
10463d0407baSopenharmony_ci		.bpp = 10,
10473d0407baSopenharmony_ci		.reg_list = ov13855_4224x3136_15fps_regs,
10483d0407baSopenharmony_ci		.link_freq_idx = 0,
10493d0407baSopenharmony_ci	},
10503d0407baSopenharmony_ci	{
10513d0407baSopenharmony_ci		.width = 2112,
10523d0407baSopenharmony_ci		.height = 1568,
10533d0407baSopenharmony_ci		.max_fps = {
10543d0407baSopenharmony_ci			.numerator = 10000,
10553d0407baSopenharmony_ci			.denominator = 300000,
10563d0407baSopenharmony_ci		},
10573d0407baSopenharmony_ci		.exp_def = 0x0644,
10583d0407baSopenharmony_ci		.hts_def = 0x08c4,
10593d0407baSopenharmony_ci		.vts_def = 0x0648,
10603d0407baSopenharmony_ci		.bpp = 10,
10613d0407baSopenharmony_ci		.reg_list = ov13855_2112x1568_30fps_regs,
10623d0407baSopenharmony_ci		.link_freq_idx = 1,
10633d0407baSopenharmony_ci	},
10643d0407baSopenharmony_ci};
10653d0407baSopenharmony_ci
10663d0407baSopenharmony_cistatic const s64 link_freq_items[] = {
10673d0407baSopenharmony_ci	OV13855_LINK_FREQ_540MHZ,
10683d0407baSopenharmony_ci	OV13855_LINK_FREQ_270MHZ,
10693d0407baSopenharmony_ci};
10703d0407baSopenharmony_ci
10713d0407baSopenharmony_cistatic const char * const ov13855_test_pattern_menu[] = {
10723d0407baSopenharmony_ci	"Disabled",
10733d0407baSopenharmony_ci	"Vertical Color Bar Type 1",
10743d0407baSopenharmony_ci	"Vertical Color Bar Type 2",
10753d0407baSopenharmony_ci	"Vertical Color Bar Type 3",
10763d0407baSopenharmony_ci	"Vertical Color Bar Type 4"
10773d0407baSopenharmony_ci};
10783d0407baSopenharmony_ci
10793d0407baSopenharmony_ci/* Write registers up to 4 at a time */
10803d0407baSopenharmony_cistatic int ov13855_write_reg(struct i2c_client *client, u16 reg,
10813d0407baSopenharmony_ci			     u32 len, u32 val)
10823d0407baSopenharmony_ci{
10833d0407baSopenharmony_ci	u32 buf_i, val_i;
10843d0407baSopenharmony_ci	u8 buf[6];
10853d0407baSopenharmony_ci	u8 *val_p;
10863d0407baSopenharmony_ci	__be32 val_be;
10873d0407baSopenharmony_ci
10883d0407baSopenharmony_ci	dev_dbg(&client->dev, "write reg(0x%x val:0x%x)!\n", reg, val);
10893d0407baSopenharmony_ci
10903d0407baSopenharmony_ci	if (len > 4)
10913d0407baSopenharmony_ci		return -EINVAL;
10923d0407baSopenharmony_ci
10933d0407baSopenharmony_ci	buf[0] = reg >> 8;
10943d0407baSopenharmony_ci	buf[1] = reg & 0xff;
10953d0407baSopenharmony_ci
10963d0407baSopenharmony_ci	val_be = cpu_to_be32(val);
10973d0407baSopenharmony_ci	val_p = (u8 *)&val_be;
10983d0407baSopenharmony_ci	buf_i = 2;
10993d0407baSopenharmony_ci	val_i = 4 - len;
11003d0407baSopenharmony_ci
11013d0407baSopenharmony_ci	while (val_i < 4)
11023d0407baSopenharmony_ci		buf[buf_i++] = val_p[val_i++];
11033d0407baSopenharmony_ci
11043d0407baSopenharmony_ci	if (i2c_master_send(client, buf, len + 2) != len + 2)
11053d0407baSopenharmony_ci		return -EIO;
11063d0407baSopenharmony_ci
11073d0407baSopenharmony_ci	return 0;
11083d0407baSopenharmony_ci}
11093d0407baSopenharmony_ci
11103d0407baSopenharmony_cistatic int ov13855_write_array(struct i2c_client *client,
11113d0407baSopenharmony_ci			       const struct regval *regs)
11123d0407baSopenharmony_ci{
11133d0407baSopenharmony_ci	u32 i;
11143d0407baSopenharmony_ci	int ret = 0;
11153d0407baSopenharmony_ci
11163d0407baSopenharmony_ci	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
11173d0407baSopenharmony_ci		ret = ov13855_write_reg(client, regs[i].addr,
11183d0407baSopenharmony_ci					OV13855_REG_VALUE_08BIT,
11193d0407baSopenharmony_ci					regs[i].val);
11203d0407baSopenharmony_ci
11213d0407baSopenharmony_ci	return ret;
11223d0407baSopenharmony_ci}
11233d0407baSopenharmony_ci
11243d0407baSopenharmony_ci/* Read registers up to 4 at a time */
11253d0407baSopenharmony_cistatic int ov13855_read_reg(struct i2c_client *client, u16 reg,
11263d0407baSopenharmony_ci			    unsigned int len, u32 *val)
11273d0407baSopenharmony_ci{
11283d0407baSopenharmony_ci	struct i2c_msg msgs[2];
11293d0407baSopenharmony_ci	u8 *data_be_p;
11303d0407baSopenharmony_ci	__be32 data_be = 0;
11313d0407baSopenharmony_ci	__be16 reg_addr_be = cpu_to_be16(reg);
11323d0407baSopenharmony_ci	int ret;
11333d0407baSopenharmony_ci
11343d0407baSopenharmony_ci	if (len > 4 || !len)
11353d0407baSopenharmony_ci		return -EINVAL;
11363d0407baSopenharmony_ci
11373d0407baSopenharmony_ci	data_be_p = (u8 *)&data_be;
11383d0407baSopenharmony_ci	/* Write register address */
11393d0407baSopenharmony_ci	msgs[0].addr = client->addr;
11403d0407baSopenharmony_ci	msgs[0].flags = 0;
11413d0407baSopenharmony_ci	msgs[0].len = 2;
11423d0407baSopenharmony_ci	msgs[0].buf = (u8 *)&reg_addr_be;
11433d0407baSopenharmony_ci
11443d0407baSopenharmony_ci	/* Read data from register */
11453d0407baSopenharmony_ci	msgs[1].addr = client->addr;
11463d0407baSopenharmony_ci	msgs[1].flags = I2C_M_RD;
11473d0407baSopenharmony_ci	msgs[1].len = len;
11483d0407baSopenharmony_ci	msgs[1].buf = &data_be_p[4 - len];
11493d0407baSopenharmony_ci
11503d0407baSopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
11513d0407baSopenharmony_ci	if (ret != ARRAY_SIZE(msgs))
11523d0407baSopenharmony_ci		return -EIO;
11533d0407baSopenharmony_ci
11543d0407baSopenharmony_ci	*val = be32_to_cpu(data_be);
11553d0407baSopenharmony_ci
11563d0407baSopenharmony_ci	return 0;
11573d0407baSopenharmony_ci}
11583d0407baSopenharmony_ci
11593d0407baSopenharmony_cistatic int ov13855_get_reso_dist(const struct ov13855_mode *mode,
11603d0407baSopenharmony_ci				 struct v4l2_mbus_framefmt *framefmt)
11613d0407baSopenharmony_ci{
11623d0407baSopenharmony_ci	return abs(mode->width - framefmt->width) +
11633d0407baSopenharmony_ci	       abs(mode->height - framefmt->height);
11643d0407baSopenharmony_ci}
11653d0407baSopenharmony_ci
11663d0407baSopenharmony_cistatic const struct ov13855_mode *
11673d0407baSopenharmony_ciov13855_find_best_fit(struct v4l2_subdev_format *fmt)
11683d0407baSopenharmony_ci{
11693d0407baSopenharmony_ci	struct v4l2_mbus_framefmt *framefmt = &fmt->format;
11703d0407baSopenharmony_ci	int dist;
11713d0407baSopenharmony_ci	int cur_best_fit = 0;
11723d0407baSopenharmony_ci	int cur_best_fit_dist = -1;
11733d0407baSopenharmony_ci	unsigned int i;
11743d0407baSopenharmony_ci
11753d0407baSopenharmony_ci	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
11763d0407baSopenharmony_ci		dist = ov13855_get_reso_dist(&supported_modes[i], framefmt);
11773d0407baSopenharmony_ci		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
11783d0407baSopenharmony_ci			cur_best_fit_dist = dist;
11793d0407baSopenharmony_ci			cur_best_fit = i;
11803d0407baSopenharmony_ci		}
11813d0407baSopenharmony_ci	}
11823d0407baSopenharmony_ci
11833d0407baSopenharmony_ci	return &supported_modes[cur_best_fit];
11843d0407baSopenharmony_ci}
11853d0407baSopenharmony_ci
11863d0407baSopenharmony_cistatic int ov13855_set_fmt(struct v4l2_subdev *sd,
11873d0407baSopenharmony_ci			   struct v4l2_subdev_pad_config *cfg,
11883d0407baSopenharmony_ci			  struct v4l2_subdev_format *fmt)
11893d0407baSopenharmony_ci{
11903d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
11913d0407baSopenharmony_ci	const struct ov13855_mode *mode;
11923d0407baSopenharmony_ci	s64 h_blank, vblank_def;
11933d0407baSopenharmony_ci	u64 pixel_rate = 0;
11943d0407baSopenharmony_ci	u32 lane_num = OV13855_LANES;
11953d0407baSopenharmony_ci
11963d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
11973d0407baSopenharmony_ci
11983d0407baSopenharmony_ci	mode = ov13855_find_best_fit(fmt);
11993d0407baSopenharmony_ci	fmt->format.code = OV13855_MEDIA_BUS_FMT;
12003d0407baSopenharmony_ci	fmt->format.width = mode->width;
12013d0407baSopenharmony_ci	fmt->format.height = mode->height;
12023d0407baSopenharmony_ci	fmt->format.field = V4L2_FIELD_NONE;
12033d0407baSopenharmony_ci	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
12043d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
12053d0407baSopenharmony_ci		*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
12063d0407baSopenharmony_ci#else
12073d0407baSopenharmony_ci		mutex_unlock(&ov13855->mutex);
12083d0407baSopenharmony_ci		return -ENOTTY;
12093d0407baSopenharmony_ci#endif
12103d0407baSopenharmony_ci	} else {
12113d0407baSopenharmony_ci		ov13855->cur_mode = mode;
12123d0407baSopenharmony_ci		h_blank = mode->hts_def - mode->width;
12133d0407baSopenharmony_ci		__v4l2_ctrl_modify_range(ov13855->hblank, h_blank,
12143d0407baSopenharmony_ci					 h_blank, 1, h_blank);
12153d0407baSopenharmony_ci		vblank_def = mode->vts_def - mode->height;
12163d0407baSopenharmony_ci		__v4l2_ctrl_modify_range(ov13855->vblank, vblank_def,
12173d0407baSopenharmony_ci					 OV13855_VTS_MAX - mode->height,
12183d0407baSopenharmony_ci					 1, vblank_def);
12193d0407baSopenharmony_ci		pixel_rate = (u32)link_freq_items[mode->link_freq_idx] / mode->bpp * 2 * lane_num;
12203d0407baSopenharmony_ci
12213d0407baSopenharmony_ci		__v4l2_ctrl_s_ctrl_int64(ov13855->pixel_rate,
12223d0407baSopenharmony_ci					 pixel_rate);
12233d0407baSopenharmony_ci		__v4l2_ctrl_s_ctrl(ov13855->link_freq,
12243d0407baSopenharmony_ci				   mode->link_freq_idx);
12253d0407baSopenharmony_ci	}
12263d0407baSopenharmony_ci
12273d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
12283d0407baSopenharmony_ci
12293d0407baSopenharmony_ci	return 0;
12303d0407baSopenharmony_ci}
12313d0407baSopenharmony_ci
12323d0407baSopenharmony_cistatic int ov13855_get_fmt(struct v4l2_subdev *sd,
12333d0407baSopenharmony_ci			   struct v4l2_subdev_pad_config *cfg,
12343d0407baSopenharmony_ci			   struct v4l2_subdev_format *fmt)
12353d0407baSopenharmony_ci{
12363d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
12373d0407baSopenharmony_ci	const struct ov13855_mode *mode = ov13855->cur_mode;
12383d0407baSopenharmony_ci
12393d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
12403d0407baSopenharmony_ci	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
12413d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
12423d0407baSopenharmony_ci		fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
12433d0407baSopenharmony_ci#else
12443d0407baSopenharmony_ci		mutex_unlock(&ov13855->mutex);
12453d0407baSopenharmony_ci		return -ENOTTY;
12463d0407baSopenharmony_ci#endif
12473d0407baSopenharmony_ci	} else {
12483d0407baSopenharmony_ci		fmt->format.width = mode->width;
12493d0407baSopenharmony_ci		fmt->format.height = mode->height;
12503d0407baSopenharmony_ci		fmt->format.code = OV13855_MEDIA_BUS_FMT;
12513d0407baSopenharmony_ci		fmt->format.field = V4L2_FIELD_NONE;
12523d0407baSopenharmony_ci	}
12533d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
12543d0407baSopenharmony_ci
12553d0407baSopenharmony_ci	return 0;
12563d0407baSopenharmony_ci}
12573d0407baSopenharmony_ci
12583d0407baSopenharmony_cistatic int ov13855_enum_mbus_code(struct v4l2_subdev *sd,
12593d0407baSopenharmony_ci				  struct v4l2_subdev_pad_config *cfg,
12603d0407baSopenharmony_ci				  struct v4l2_subdev_mbus_code_enum *code)
12613d0407baSopenharmony_ci{
12623d0407baSopenharmony_ci	if (code->index != 0)
12633d0407baSopenharmony_ci		return -EINVAL;
12643d0407baSopenharmony_ci	code->code = OV13855_MEDIA_BUS_FMT;
12653d0407baSopenharmony_ci
12663d0407baSopenharmony_ci	return 0;
12673d0407baSopenharmony_ci}
12683d0407baSopenharmony_ci
12693d0407baSopenharmony_cistatic int ov13855_enum_frame_sizes(struct v4l2_subdev *sd,
12703d0407baSopenharmony_ci				    struct v4l2_subdev_pad_config *cfg,
12713d0407baSopenharmony_ci				   struct v4l2_subdev_frame_size_enum *fse)
12723d0407baSopenharmony_ci{
12733d0407baSopenharmony_ci	if (fse->index >= ARRAY_SIZE(supported_modes))
12743d0407baSopenharmony_ci		return -EINVAL;
12753d0407baSopenharmony_ci
12763d0407baSopenharmony_ci	if (fse->code != OV13855_MEDIA_BUS_FMT)
12773d0407baSopenharmony_ci		return -EINVAL;
12783d0407baSopenharmony_ci
12793d0407baSopenharmony_ci	fse->min_width  = supported_modes[fse->index].width;
12803d0407baSopenharmony_ci	fse->max_width  = supported_modes[fse->index].width;
12813d0407baSopenharmony_ci	fse->max_height = supported_modes[fse->index].height;
12823d0407baSopenharmony_ci	fse->min_height = supported_modes[fse->index].height;
12833d0407baSopenharmony_ci
12843d0407baSopenharmony_ci	return 0;
12853d0407baSopenharmony_ci}
12863d0407baSopenharmony_ci
12873d0407baSopenharmony_cistatic int ov13855_enable_test_pattern(struct ov13855 *ov13855, u32 pattern)
12883d0407baSopenharmony_ci{
12893d0407baSopenharmony_ci	u32 val;
12903d0407baSopenharmony_ci
12913d0407baSopenharmony_ci	if (pattern)
12923d0407baSopenharmony_ci		val = (pattern - 1) | OV13855_TEST_PATTERN_ENABLE;
12933d0407baSopenharmony_ci	else
12943d0407baSopenharmony_ci		val = OV13855_TEST_PATTERN_DISABLE;
12953d0407baSopenharmony_ci
12963d0407baSopenharmony_ci	return ov13855_write_reg(ov13855->client,
12973d0407baSopenharmony_ci				 OV13855_REG_TEST_PATTERN,
12983d0407baSopenharmony_ci				 OV13855_REG_VALUE_08BIT,
12993d0407baSopenharmony_ci				 val);
13003d0407baSopenharmony_ci}
13013d0407baSopenharmony_ci
13023d0407baSopenharmony_cistatic int ov13855_g_frame_interval(struct v4l2_subdev *sd,
13033d0407baSopenharmony_ci				    struct v4l2_subdev_frame_interval *fi)
13043d0407baSopenharmony_ci{
13053d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
13063d0407baSopenharmony_ci	const struct ov13855_mode *mode = ov13855->cur_mode;
13073d0407baSopenharmony_ci
13083d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
13093d0407baSopenharmony_ci	fi->interval = mode->max_fps;
13103d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
13113d0407baSopenharmony_ci
13123d0407baSopenharmony_ci	return 0;
13133d0407baSopenharmony_ci}
13143d0407baSopenharmony_ci
13153d0407baSopenharmony_cistatic void ov13855_get_module_inf(struct ov13855 *ov13855,
13163d0407baSopenharmony_ci				   struct rkmodule_inf *inf)
13173d0407baSopenharmony_ci{
13183d0407baSopenharmony_ci	memset(inf, 0, sizeof(*inf));
13193d0407baSopenharmony_ci	strscpy(inf->base.sensor, OV13855_NAME, sizeof(inf->base.sensor));
13203d0407baSopenharmony_ci	strscpy(inf->base.module, ov13855->module_name,
13213d0407baSopenharmony_ci		sizeof(inf->base.module));
13223d0407baSopenharmony_ci	strscpy(inf->base.lens, ov13855->len_name, sizeof(inf->base.lens));
13233d0407baSopenharmony_ci}
13243d0407baSopenharmony_ci
13253d0407baSopenharmony_cistatic long ov13855_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
13263d0407baSopenharmony_ci{
13273d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
13283d0407baSopenharmony_ci	long ret = 0;
13293d0407baSopenharmony_ci	u32 stream = 0;
13303d0407baSopenharmony_ci
13313d0407baSopenharmony_ci	switch (cmd) {
13323d0407baSopenharmony_ci	case RKMODULE_GET_MODULE_INFO:
13333d0407baSopenharmony_ci		ov13855_get_module_inf(ov13855, (struct rkmodule_inf *)arg);
13343d0407baSopenharmony_ci		break;
13353d0407baSopenharmony_ci	case RKMODULE_SET_QUICK_STREAM:
13363d0407baSopenharmony_ci
13373d0407baSopenharmony_ci		stream = *((u32 *)arg);
13383d0407baSopenharmony_ci
13393d0407baSopenharmony_ci		if (stream)
13403d0407baSopenharmony_ci			ret = ov13855_write_reg(ov13855->client,
13413d0407baSopenharmony_ci				 OV13855_REG_CTRL_MODE,
13423d0407baSopenharmony_ci				 OV13855_REG_VALUE_08BIT,
13433d0407baSopenharmony_ci				 OV13855_MODE_STREAMING);
13443d0407baSopenharmony_ci		else
13453d0407baSopenharmony_ci			ret = ov13855_write_reg(ov13855->client,
13463d0407baSopenharmony_ci				 OV13855_REG_CTRL_MODE,
13473d0407baSopenharmony_ci				 OV13855_REG_VALUE_08BIT,
13483d0407baSopenharmony_ci				 OV13855_MODE_SW_STANDBY);
13493d0407baSopenharmony_ci		break;
13503d0407baSopenharmony_ci	default:
13513d0407baSopenharmony_ci		ret = -ENOIOCTLCMD;
13523d0407baSopenharmony_ci		break;
13533d0407baSopenharmony_ci	}
13543d0407baSopenharmony_ci
13553d0407baSopenharmony_ci	return ret;
13563d0407baSopenharmony_ci}
13573d0407baSopenharmony_ci
13583d0407baSopenharmony_ci#ifdef CONFIG_COMPAT
13593d0407baSopenharmony_cistatic long ov13855_compat_ioctl32(struct v4l2_subdev *sd,
13603d0407baSopenharmony_ci				   unsigned int cmd, unsigned long arg)
13613d0407baSopenharmony_ci{
13623d0407baSopenharmony_ci	void __user *up = compat_ptr(arg);
13633d0407baSopenharmony_ci	struct rkmodule_inf *inf;
13643d0407baSopenharmony_ci	struct rkmodule_awb_cfg *cfg;
13653d0407baSopenharmony_ci	long ret = 0;
13663d0407baSopenharmony_ci	u32 stream = 0;
13673d0407baSopenharmony_ci
13683d0407baSopenharmony_ci	switch (cmd) {
13693d0407baSopenharmony_ci	case RKMODULE_GET_MODULE_INFO:
13703d0407baSopenharmony_ci		inf = kzalloc(sizeof(*inf), GFP_KERNEL);
13713d0407baSopenharmony_ci		if (!inf) {
13723d0407baSopenharmony_ci			ret = -ENOMEM;
13733d0407baSopenharmony_ci			return ret;
13743d0407baSopenharmony_ci		}
13753d0407baSopenharmony_ci
13763d0407baSopenharmony_ci		ret = ov13855_ioctl(sd, cmd, inf);
13773d0407baSopenharmony_ci		if (!ret) {
13783d0407baSopenharmony_ci			ret = copy_to_user(up, inf, sizeof(*inf));
13793d0407baSopenharmony_ci			if (ret)
13803d0407baSopenharmony_ci				ret = -EFAULT;
13813d0407baSopenharmony_ci		}
13823d0407baSopenharmony_ci		kfree(inf);
13833d0407baSopenharmony_ci		break;
13843d0407baSopenharmony_ci	case RKMODULE_AWB_CFG:
13853d0407baSopenharmony_ci		cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
13863d0407baSopenharmony_ci		if (!cfg) {
13873d0407baSopenharmony_ci			ret = -ENOMEM;
13883d0407baSopenharmony_ci			return ret;
13893d0407baSopenharmony_ci		}
13903d0407baSopenharmony_ci
13913d0407baSopenharmony_ci		ret = copy_from_user(cfg, up, sizeof(*cfg));
13923d0407baSopenharmony_ci		if (!ret)
13933d0407baSopenharmony_ci			ret = ov13855_ioctl(sd, cmd, cfg);
13943d0407baSopenharmony_ci		else
13953d0407baSopenharmony_ci			ret = -EFAULT;
13963d0407baSopenharmony_ci		kfree(cfg);
13973d0407baSopenharmony_ci		break;
13983d0407baSopenharmony_ci	case RKMODULE_SET_QUICK_STREAM:
13993d0407baSopenharmony_ci		ret = copy_from_user(&stream, up, sizeof(u32));
14003d0407baSopenharmony_ci		if (!ret)
14013d0407baSopenharmony_ci			ret = ov13855_ioctl(sd, cmd, &stream);
14023d0407baSopenharmony_ci		else
14033d0407baSopenharmony_ci			ret = -EFAULT;
14043d0407baSopenharmony_ci		break;
14053d0407baSopenharmony_ci	default:
14063d0407baSopenharmony_ci		ret = -ENOIOCTLCMD;
14073d0407baSopenharmony_ci		break;
14083d0407baSopenharmony_ci	}
14093d0407baSopenharmony_ci
14103d0407baSopenharmony_ci	return ret;
14113d0407baSopenharmony_ci}
14123d0407baSopenharmony_ci#endif
14133d0407baSopenharmony_ci
14143d0407baSopenharmony_cistatic int __ov13855_start_stream(struct ov13855 *ov13855)
14153d0407baSopenharmony_ci{
14163d0407baSopenharmony_ci	int ret;
14173d0407baSopenharmony_ci
14183d0407baSopenharmony_ci	ret = ov13855_write_array(ov13855->client, ov13855->cur_mode->reg_list);
14193d0407baSopenharmony_ci	if (ret)
14203d0407baSopenharmony_ci		return ret;
14213d0407baSopenharmony_ci
14223d0407baSopenharmony_ci	/* In case these controls are set before streaming */
14233d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
14243d0407baSopenharmony_ci	ret = v4l2_ctrl_handler_setup(&ov13855->ctrl_handler);
14253d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
14263d0407baSopenharmony_ci	if (ret)
14273d0407baSopenharmony_ci		return ret;
14283d0407baSopenharmony_ci
14293d0407baSopenharmony_ci	return ov13855_write_reg(ov13855->client,
14303d0407baSopenharmony_ci				 OV13855_REG_CTRL_MODE,
14313d0407baSopenharmony_ci				 OV13855_REG_VALUE_08BIT,
14323d0407baSopenharmony_ci				 OV13855_MODE_STREAMING);
14333d0407baSopenharmony_ci}
14343d0407baSopenharmony_ci
14353d0407baSopenharmony_cistatic int __ov13855_stop_stream(struct ov13855 *ov13855)
14363d0407baSopenharmony_ci{
14373d0407baSopenharmony_ci	return ov13855_write_reg(ov13855->client,
14383d0407baSopenharmony_ci				 OV13855_REG_CTRL_MODE,
14393d0407baSopenharmony_ci				 OV13855_REG_VALUE_08BIT,
14403d0407baSopenharmony_ci				 OV13855_MODE_SW_STANDBY);
14413d0407baSopenharmony_ci}
14423d0407baSopenharmony_ci
14433d0407baSopenharmony_cistatic int ov13855_s_stream(struct v4l2_subdev *sd, int on)
14443d0407baSopenharmony_ci{
14453d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
14463d0407baSopenharmony_ci	struct i2c_client *client = ov13855->client;
14473d0407baSopenharmony_ci	int ret = 0;
14483d0407baSopenharmony_ci
14493d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
14503d0407baSopenharmony_ci	on = !!on;
14513d0407baSopenharmony_ci	if (on == ov13855->streaming)
14523d0407baSopenharmony_ci		goto unlock_and_return;
14533d0407baSopenharmony_ci
14543d0407baSopenharmony_ci	if (on) {
14553d0407baSopenharmony_ci		ret = pm_runtime_get_sync(&client->dev);
14563d0407baSopenharmony_ci		if (ret < 0) {
14573d0407baSopenharmony_ci			pm_runtime_put_noidle(&client->dev);
14583d0407baSopenharmony_ci			goto unlock_and_return;
14593d0407baSopenharmony_ci		}
14603d0407baSopenharmony_ci
14613d0407baSopenharmony_ci		ret = __ov13855_start_stream(ov13855);
14623d0407baSopenharmony_ci		if (ret) {
14633d0407baSopenharmony_ci			v4l2_err(sd, "start stream failed while write regs\n");
14643d0407baSopenharmony_ci			pm_runtime_put(&client->dev);
14653d0407baSopenharmony_ci			goto unlock_and_return;
14663d0407baSopenharmony_ci		}
14673d0407baSopenharmony_ci	} else {
14683d0407baSopenharmony_ci		__ov13855_stop_stream(ov13855);
14693d0407baSopenharmony_ci		pm_runtime_put(&client->dev);
14703d0407baSopenharmony_ci	}
14713d0407baSopenharmony_ci
14723d0407baSopenharmony_ci	ov13855->streaming = on;
14733d0407baSopenharmony_ci
14743d0407baSopenharmony_ciunlock_and_return:
14753d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
14763d0407baSopenharmony_ci
14773d0407baSopenharmony_ci	return ret;
14783d0407baSopenharmony_ci}
14793d0407baSopenharmony_ci
14803d0407baSopenharmony_cistatic int ov13855_s_power(struct v4l2_subdev *sd, int on)
14813d0407baSopenharmony_ci{
14823d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
14833d0407baSopenharmony_ci	struct i2c_client *client = ov13855->client;
14843d0407baSopenharmony_ci	int ret = 0;
14853d0407baSopenharmony_ci
14863d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
14873d0407baSopenharmony_ci
14883d0407baSopenharmony_ci	/* If the power state is not modified - no work to do. */
14893d0407baSopenharmony_ci	if (ov13855->power_on == !!on)
14903d0407baSopenharmony_ci		goto unlock_and_return;
14913d0407baSopenharmony_ci
14923d0407baSopenharmony_ci	if (on) {
14933d0407baSopenharmony_ci		ret = pm_runtime_get_sync(&client->dev);
14943d0407baSopenharmony_ci		if (ret < 0) {
14953d0407baSopenharmony_ci			pm_runtime_put_noidle(&client->dev);
14963d0407baSopenharmony_ci			goto unlock_and_return;
14973d0407baSopenharmony_ci		}
14983d0407baSopenharmony_ci
14993d0407baSopenharmony_ci		ret = ov13855_write_array(ov13855->client, ov13855_global_regs);
15003d0407baSopenharmony_ci		if (ret) {
15013d0407baSopenharmony_ci			v4l2_err(sd, "could not set init registers\n");
15023d0407baSopenharmony_ci			pm_runtime_put_noidle(&client->dev);
15033d0407baSopenharmony_ci			goto unlock_and_return;
15043d0407baSopenharmony_ci		}
15053d0407baSopenharmony_ci
15063d0407baSopenharmony_ci		ov13855->power_on = true;
15073d0407baSopenharmony_ci	} else {
15083d0407baSopenharmony_ci		pm_runtime_put(&client->dev);
15093d0407baSopenharmony_ci		ov13855->power_on = false;
15103d0407baSopenharmony_ci	}
15113d0407baSopenharmony_ci
15123d0407baSopenharmony_ciunlock_and_return:
15133d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
15143d0407baSopenharmony_ci
15153d0407baSopenharmony_ci	return ret;
15163d0407baSopenharmony_ci}
15173d0407baSopenharmony_ci
15183d0407baSopenharmony_ci/* Calculate the delay in us by clock rate and clock cycles */
15193d0407baSopenharmony_cistatic inline u32 ov13855_cal_delay(u32 cycles)
15203d0407baSopenharmony_ci{
15213d0407baSopenharmony_ci	return DIV_ROUND_UP(cycles, OV13855_XVCLK_FREQ / 1000 / 1000);
15223d0407baSopenharmony_ci}
15233d0407baSopenharmony_ci
15243d0407baSopenharmony_cistatic int __ov13855_power_on(struct ov13855 *ov13855)
15253d0407baSopenharmony_ci{
15263d0407baSopenharmony_ci	int ret;
15273d0407baSopenharmony_ci	u32 delay_us;
15283d0407baSopenharmony_ci	struct device *dev = &ov13855->client->dev;
15293d0407baSopenharmony_ci
15303d0407baSopenharmony_ci	if (!IS_ERR(ov13855->power_gpio))
15313d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->power_gpio, 1);
15323d0407baSopenharmony_ci
15333d0407baSopenharmony_ci	usleep_range(1000, 2000);
15343d0407baSopenharmony_ci
15353d0407baSopenharmony_ci	if (!IS_ERR_OR_NULL(ov13855->pins_default)) {
15363d0407baSopenharmony_ci		ret = pinctrl_select_state(ov13855->pinctrl,
15373d0407baSopenharmony_ci					   ov13855->pins_default);
15383d0407baSopenharmony_ci		if (ret < 0)
15393d0407baSopenharmony_ci			dev_err(dev, "could not set pins\n");
15403d0407baSopenharmony_ci	}
15413d0407baSopenharmony_ci	ret = clk_set_rate(ov13855->xvclk, OV13855_XVCLK_FREQ);
15423d0407baSopenharmony_ci	if (ret < 0)
15433d0407baSopenharmony_ci		dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
15443d0407baSopenharmony_ci	if (clk_get_rate(ov13855->xvclk) != OV13855_XVCLK_FREQ)
15453d0407baSopenharmony_ci		dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
15463d0407baSopenharmony_ci	ret = clk_prepare_enable(ov13855->xvclk);
15473d0407baSopenharmony_ci	if (ret < 0) {
15483d0407baSopenharmony_ci		dev_err(dev, "Failed to enable xvclk\n");
15493d0407baSopenharmony_ci		return ret;
15503d0407baSopenharmony_ci	}
15513d0407baSopenharmony_ci	if (!IS_ERR(ov13855->reset_gpio))
15523d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->reset_gpio, 0);
15533d0407baSopenharmony_ci
15543d0407baSopenharmony_ci	ret = regulator_bulk_enable(OV13855_NUM_SUPPLIES, ov13855->supplies);
15553d0407baSopenharmony_ci	if (ret < 0) {
15563d0407baSopenharmony_ci		dev_err(dev, "Failed to enable regulators\n");
15573d0407baSopenharmony_ci		goto disable_clk;
15583d0407baSopenharmony_ci	}
15593d0407baSopenharmony_ci
15603d0407baSopenharmony_ci	if (!IS_ERR(ov13855->reset_gpio))
15613d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->reset_gpio, 1);
15623d0407baSopenharmony_ci
15633d0407baSopenharmony_ci	usleep_range(500, 1000);
15643d0407baSopenharmony_ci	if (!IS_ERR(ov13855->pwdn_gpio))
15653d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->pwdn_gpio, 1);
15663d0407baSopenharmony_ci
15673d0407baSopenharmony_ci	/* 8192 cycles prior to first SCCB transaction */
15683d0407baSopenharmony_ci	delay_us = ov13855_cal_delay(8192);
15693d0407baSopenharmony_ci	usleep_range(delay_us, delay_us * 2);
15703d0407baSopenharmony_ci
15713d0407baSopenharmony_ci	return 0;
15723d0407baSopenharmony_ci
15733d0407baSopenharmony_cidisable_clk:
15743d0407baSopenharmony_ci	clk_disable_unprepare(ov13855->xvclk);
15753d0407baSopenharmony_ci
15763d0407baSopenharmony_ci	return ret;
15773d0407baSopenharmony_ci}
15783d0407baSopenharmony_ci
15793d0407baSopenharmony_cistatic void __ov13855_power_off(struct ov13855 *ov13855)
15803d0407baSopenharmony_ci{
15813d0407baSopenharmony_ci	int ret;
15823d0407baSopenharmony_ci	struct device *dev = &ov13855->client->dev;
15833d0407baSopenharmony_ci
15843d0407baSopenharmony_ci	if (!IS_ERR(ov13855->pwdn_gpio))
15853d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->pwdn_gpio, 0);
15863d0407baSopenharmony_ci	clk_disable_unprepare(ov13855->xvclk);
15873d0407baSopenharmony_ci	if (!IS_ERR(ov13855->reset_gpio))
15883d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->reset_gpio, 0);
15893d0407baSopenharmony_ci
15903d0407baSopenharmony_ci	if (!IS_ERR_OR_NULL(ov13855->pins_sleep)) {
15913d0407baSopenharmony_ci		ret = pinctrl_select_state(ov13855->pinctrl,
15923d0407baSopenharmony_ci					   ov13855->pins_sleep);
15933d0407baSopenharmony_ci		if (ret < 0)
15943d0407baSopenharmony_ci			dev_dbg(dev, "could not set pins\n");
15953d0407baSopenharmony_ci	}
15963d0407baSopenharmony_ci	if (!IS_ERR(ov13855->power_gpio))
15973d0407baSopenharmony_ci		gpiod_set_value_cansleep(ov13855->power_gpio, 0);
15983d0407baSopenharmony_ci
15993d0407baSopenharmony_ci	regulator_bulk_disable(OV13855_NUM_SUPPLIES, ov13855->supplies);
16003d0407baSopenharmony_ci}
16013d0407baSopenharmony_ci
16023d0407baSopenharmony_cistatic int ov13855_runtime_resume(struct device *dev)
16033d0407baSopenharmony_ci{
16043d0407baSopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
16053d0407baSopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
16063d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
16073d0407baSopenharmony_ci
16083d0407baSopenharmony_ci	return __ov13855_power_on(ov13855);
16093d0407baSopenharmony_ci}
16103d0407baSopenharmony_ci
16113d0407baSopenharmony_cistatic int ov13855_runtime_suspend(struct device *dev)
16123d0407baSopenharmony_ci{
16133d0407baSopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
16143d0407baSopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
16153d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
16163d0407baSopenharmony_ci
16173d0407baSopenharmony_ci	__ov13855_power_off(ov13855);
16183d0407baSopenharmony_ci
16193d0407baSopenharmony_ci	return 0;
16203d0407baSopenharmony_ci}
16213d0407baSopenharmony_ci
16223d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
16233d0407baSopenharmony_cistatic int ov13855_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
16243d0407baSopenharmony_ci{
16253d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
16263d0407baSopenharmony_ci	struct v4l2_mbus_framefmt *try_fmt =
16273d0407baSopenharmony_ci				v4l2_subdev_get_try_format(sd, fh->pad, 0);
16283d0407baSopenharmony_ci	const struct ov13855_mode *def_mode = &supported_modes[0];
16293d0407baSopenharmony_ci
16303d0407baSopenharmony_ci	mutex_lock(&ov13855->mutex);
16313d0407baSopenharmony_ci	/* Initialize try_fmt */
16323d0407baSopenharmony_ci	try_fmt->width = def_mode->width;
16333d0407baSopenharmony_ci	try_fmt->height = def_mode->height;
16343d0407baSopenharmony_ci	try_fmt->code = OV13855_MEDIA_BUS_FMT;
16353d0407baSopenharmony_ci	try_fmt->field = V4L2_FIELD_NONE;
16363d0407baSopenharmony_ci
16373d0407baSopenharmony_ci	mutex_unlock(&ov13855->mutex);
16383d0407baSopenharmony_ci	/* No crop or compose */
16393d0407baSopenharmony_ci
16403d0407baSopenharmony_ci	return 0;
16413d0407baSopenharmony_ci}
16423d0407baSopenharmony_ci#endif
16433d0407baSopenharmony_ci
16443d0407baSopenharmony_cistatic int ov13855_enum_frame_interval(struct v4l2_subdev *sd,
16453d0407baSopenharmony_ci				       struct v4l2_subdev_pad_config *cfg,
16463d0407baSopenharmony_ci				       struct v4l2_subdev_frame_interval_enum *fie)
16473d0407baSopenharmony_ci{
16483d0407baSopenharmony_ci	if (fie->index >= ARRAY_SIZE(supported_modes))
16493d0407baSopenharmony_ci		return -EINVAL;
16503d0407baSopenharmony_ci
16513d0407baSopenharmony_ci	if (fie->code != OV13855_MEDIA_BUS_FMT)
16523d0407baSopenharmony_ci		return -EINVAL;
16533d0407baSopenharmony_ci
16543d0407baSopenharmony_ci	fie->width = supported_modes[fie->index].width;
16553d0407baSopenharmony_ci	fie->height = supported_modes[fie->index].height;
16563d0407baSopenharmony_ci	fie->interval = supported_modes[fie->index].max_fps;
16573d0407baSopenharmony_ci
16583d0407baSopenharmony_ci	return 0;
16593d0407baSopenharmony_ci}
16603d0407baSopenharmony_ci
16613d0407baSopenharmony_cistatic int ov13855_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
16623d0407baSopenharmony_ci				struct v4l2_mbus_config *config)
16633d0407baSopenharmony_ci{
16643d0407baSopenharmony_ci	if (2 == OV13855_LANES) {
16653d0407baSopenharmony_ci		config->type = V4L2_MBUS_CSI2_DPHY;
16663d0407baSopenharmony_ci		config->flags = V4L2_MBUS_CSI2_2_LANE |
16673d0407baSopenharmony_ci				V4L2_MBUS_CSI2_CHANNEL_0 |
16683d0407baSopenharmony_ci				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
16693d0407baSopenharmony_ci	} else if (4 == OV13855_LANES) {
16703d0407baSopenharmony_ci		config->type = V4L2_MBUS_CSI2_DPHY;
16713d0407baSopenharmony_ci		config->flags = V4L2_MBUS_CSI2_4_LANE |
16723d0407baSopenharmony_ci				V4L2_MBUS_CSI2_CHANNEL_0 |
16733d0407baSopenharmony_ci				V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
16743d0407baSopenharmony_ci	}
16753d0407baSopenharmony_ci
16763d0407baSopenharmony_ci	return 0;
16773d0407baSopenharmony_ci}
16783d0407baSopenharmony_ci
16793d0407baSopenharmony_cistatic int ov13855_get_selection(struct v4l2_subdev *sd,
16803d0407baSopenharmony_ci				struct v4l2_subdev_pad_config *cfg,
16813d0407baSopenharmony_ci				struct v4l2_subdev_selection *sel)
16823d0407baSopenharmony_ci{
16833d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
16843d0407baSopenharmony_ci
16853d0407baSopenharmony_ci	if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
16863d0407baSopenharmony_ci		sel->r.left = 0;
16873d0407baSopenharmony_ci		sel->r.width = ov13855->cur_mode->width;
16883d0407baSopenharmony_ci		sel->r.top = 0;
16893d0407baSopenharmony_ci		sel->r.height = ov13855->cur_mode->height;
16903d0407baSopenharmony_ci		return 0;
16913d0407baSopenharmony_ci	}
16923d0407baSopenharmony_ci
16933d0407baSopenharmony_ci	return -EINVAL;
16943d0407baSopenharmony_ci}
16953d0407baSopenharmony_ci
16963d0407baSopenharmony_cistatic const struct dev_pm_ops ov13855_pm_ops = {
16973d0407baSopenharmony_ci	SET_RUNTIME_PM_OPS(ov13855_runtime_suspend,
16983d0407baSopenharmony_ci			   ov13855_runtime_resume, NULL)
16993d0407baSopenharmony_ci};
17003d0407baSopenharmony_ci
17013d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
17023d0407baSopenharmony_cistatic const struct v4l2_subdev_internal_ops ov13855_internal_ops = {
17033d0407baSopenharmony_ci	.open = ov13855_open,
17043d0407baSopenharmony_ci};
17053d0407baSopenharmony_ci#endif
17063d0407baSopenharmony_ci
17073d0407baSopenharmony_cistatic const struct v4l2_subdev_core_ops ov13855_core_ops = {
17083d0407baSopenharmony_ci	.s_power = ov13855_s_power,
17093d0407baSopenharmony_ci	.ioctl = ov13855_ioctl,
17103d0407baSopenharmony_ci#ifdef CONFIG_COMPAT
17113d0407baSopenharmony_ci	.compat_ioctl32 = ov13855_compat_ioctl32,
17123d0407baSopenharmony_ci#endif
17133d0407baSopenharmony_ci};
17143d0407baSopenharmony_ci
17153d0407baSopenharmony_cistatic const struct v4l2_subdev_video_ops ov13855_video_ops = {
17163d0407baSopenharmony_ci	.s_stream = ov13855_s_stream,
17173d0407baSopenharmony_ci	.g_frame_interval = ov13855_g_frame_interval,
17183d0407baSopenharmony_ci};
17193d0407baSopenharmony_ci
17203d0407baSopenharmony_cistatic const struct v4l2_subdev_pad_ops ov13855_pad_ops = {
17213d0407baSopenharmony_ci	.enum_mbus_code = ov13855_enum_mbus_code,
17223d0407baSopenharmony_ci	.enum_frame_size = ov13855_enum_frame_sizes,
17233d0407baSopenharmony_ci	.enum_frame_interval = ov13855_enum_frame_interval,
17243d0407baSopenharmony_ci	.get_fmt = ov13855_get_fmt,
17253d0407baSopenharmony_ci	.set_fmt = ov13855_set_fmt,
17263d0407baSopenharmony_ci	.get_selection = ov13855_get_selection,
17273d0407baSopenharmony_ci	.get_mbus_config = ov13855_g_mbus_config,
17283d0407baSopenharmony_ci};
17293d0407baSopenharmony_ci
17303d0407baSopenharmony_cistatic const struct v4l2_subdev_ops ov13855_subdev_ops = {
17313d0407baSopenharmony_ci	.core	= &ov13855_core_ops,
17323d0407baSopenharmony_ci	.video	= &ov13855_video_ops,
17333d0407baSopenharmony_ci	.pad	= &ov13855_pad_ops,
17343d0407baSopenharmony_ci};
17353d0407baSopenharmony_ci
17363d0407baSopenharmony_cistatic int ov13855_set_ctrl(struct v4l2_ctrl *ctrl)
17373d0407baSopenharmony_ci{
17383d0407baSopenharmony_ci	struct ov13855 *ov13855 = container_of(ctrl->handler,
17393d0407baSopenharmony_ci					     struct ov13855, ctrl_handler);
17403d0407baSopenharmony_ci	struct i2c_client *client = ov13855->client;
17413d0407baSopenharmony_ci	s64 max;
17423d0407baSopenharmony_ci	int ret = 0;
17433d0407baSopenharmony_ci
17443d0407baSopenharmony_ci	/* Propagate change of current control to all related controls */
17453d0407baSopenharmony_ci	switch (ctrl->id) {
17463d0407baSopenharmony_ci	case V4L2_CID_VBLANK:
17473d0407baSopenharmony_ci		/* Update max exposure while meeting expected vblanking */
17483d0407baSopenharmony_ci		max = ov13855->cur_mode->height + ctrl->val - 4;
17493d0407baSopenharmony_ci		__v4l2_ctrl_modify_range(ov13855->exposure,
17503d0407baSopenharmony_ci					 ov13855->exposure->minimum, max,
17513d0407baSopenharmony_ci					 ov13855->exposure->step,
17523d0407baSopenharmony_ci					 ov13855->exposure->default_value);
17533d0407baSopenharmony_ci		break;
17543d0407baSopenharmony_ci	}
17553d0407baSopenharmony_ci
17563d0407baSopenharmony_ci	if (!pm_runtime_get_if_in_use(&client->dev))
17573d0407baSopenharmony_ci		return 0;
17583d0407baSopenharmony_ci
17593d0407baSopenharmony_ci	switch (ctrl->id) {
17603d0407baSopenharmony_ci	case V4L2_CID_EXPOSURE:
17613d0407baSopenharmony_ci		/* 4 least significant bits of expsoure are fractional part */
17623d0407baSopenharmony_ci		ret = ov13855_write_reg(ov13855->client,
17633d0407baSopenharmony_ci					OV13855_REG_EXPOSURE,
17643d0407baSopenharmony_ci					OV13855_REG_VALUE_24BIT,
17653d0407baSopenharmony_ci					ctrl->val << 4);
17663d0407baSopenharmony_ci		break;
17673d0407baSopenharmony_ci	case V4L2_CID_ANALOGUE_GAIN:
17683d0407baSopenharmony_ci		ret = ov13855_write_reg(ov13855->client,
17693d0407baSopenharmony_ci					OV13855_REG_GAIN_H,
17703d0407baSopenharmony_ci					OV13855_REG_VALUE_08BIT,
17713d0407baSopenharmony_ci					(ctrl->val >> OV13855_GAIN_H_SHIFT) &
17723d0407baSopenharmony_ci					OV13855_GAIN_H_MASK);
17733d0407baSopenharmony_ci		ret |= ov13855_write_reg(ov13855->client,
17743d0407baSopenharmony_ci					 OV13855_REG_GAIN_L,
17753d0407baSopenharmony_ci					 OV13855_REG_VALUE_08BIT,
17763d0407baSopenharmony_ci					 ctrl->val & OV13855_GAIN_L_MASK);
17773d0407baSopenharmony_ci		break;
17783d0407baSopenharmony_ci	case V4L2_CID_VBLANK:
17793d0407baSopenharmony_ci		ret = ov13855_write_reg(ov13855->client,
17803d0407baSopenharmony_ci					OV13855_REG_VTS,
17813d0407baSopenharmony_ci					OV13855_REG_VALUE_16BIT,
17823d0407baSopenharmony_ci					ctrl->val + ov13855->cur_mode->height);
17833d0407baSopenharmony_ci		break;
17843d0407baSopenharmony_ci	case V4L2_CID_TEST_PATTERN:
17853d0407baSopenharmony_ci		ret = ov13855_enable_test_pattern(ov13855, ctrl->val);
17863d0407baSopenharmony_ci		break;
17873d0407baSopenharmony_ci	default:
17883d0407baSopenharmony_ci		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
17893d0407baSopenharmony_ci			 __func__, ctrl->id, ctrl->val);
17903d0407baSopenharmony_ci		break;
17913d0407baSopenharmony_ci	}
17923d0407baSopenharmony_ci
17933d0407baSopenharmony_ci	pm_runtime_put(&client->dev);
17943d0407baSopenharmony_ci
17953d0407baSopenharmony_ci	return ret;
17963d0407baSopenharmony_ci}
17973d0407baSopenharmony_ci
17983d0407baSopenharmony_cistatic const struct v4l2_ctrl_ops ov13855_ctrl_ops = {
17993d0407baSopenharmony_ci	.s_ctrl = ov13855_set_ctrl,
18003d0407baSopenharmony_ci};
18013d0407baSopenharmony_ci
18023d0407baSopenharmony_cistatic int ov13855_initialize_controls(struct ov13855 *ov13855)
18033d0407baSopenharmony_ci{
18043d0407baSopenharmony_ci	const struct ov13855_mode *mode;
18053d0407baSopenharmony_ci	struct v4l2_ctrl_handler *handler;
18063d0407baSopenharmony_ci	s64 exposure_max, vblank_def;
18073d0407baSopenharmony_ci	u32 h_blank;
18083d0407baSopenharmony_ci	int ret;
18093d0407baSopenharmony_ci	u64 dst_pixel_rate = 0;
18103d0407baSopenharmony_ci	u32 lane_num = OV13855_LANES;
18113d0407baSopenharmony_ci
18123d0407baSopenharmony_ci	handler = &ov13855->ctrl_handler;
18133d0407baSopenharmony_ci	mode = ov13855->cur_mode;
18143d0407baSopenharmony_ci	ret = v4l2_ctrl_handler_init(handler, 8);
18153d0407baSopenharmony_ci	if (ret)
18163d0407baSopenharmony_ci		return ret;
18173d0407baSopenharmony_ci	handler->lock = &ov13855->mutex;
18183d0407baSopenharmony_ci
18193d0407baSopenharmony_ci	ov13855->link_freq = v4l2_ctrl_new_int_menu(handler, NULL,
18203d0407baSopenharmony_ci			V4L2_CID_LINK_FREQ,
18213d0407baSopenharmony_ci			1, 0, link_freq_items);
18223d0407baSopenharmony_ci
18233d0407baSopenharmony_ci	dst_pixel_rate = (u32)link_freq_items[mode->link_freq_idx] / mode->bpp * 2 * lane_num;
18243d0407baSopenharmony_ci
18253d0407baSopenharmony_ci	ov13855->pixel_rate = v4l2_ctrl_new_std(handler, NULL,
18263d0407baSopenharmony_ci			V4L2_CID_PIXEL_RATE,
18273d0407baSopenharmony_ci			0, OV13855_PIXEL_RATE,
18283d0407baSopenharmony_ci			1, dst_pixel_rate);
18293d0407baSopenharmony_ci
18303d0407baSopenharmony_ci	__v4l2_ctrl_s_ctrl(ov13855->link_freq,
18313d0407baSopenharmony_ci			   mode->link_freq_idx);
18323d0407baSopenharmony_ci
18333d0407baSopenharmony_ci	h_blank = mode->hts_def - mode->width;
18343d0407baSopenharmony_ci	ov13855->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
18353d0407baSopenharmony_ci				h_blank, h_blank, 1, h_blank);
18363d0407baSopenharmony_ci	if (ov13855->hblank)
18373d0407baSopenharmony_ci		ov13855->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
18383d0407baSopenharmony_ci
18393d0407baSopenharmony_ci	vblank_def = mode->vts_def - mode->height;
18403d0407baSopenharmony_ci	ov13855->vblank = v4l2_ctrl_new_std(handler, &ov13855_ctrl_ops,
18413d0407baSopenharmony_ci				V4L2_CID_VBLANK, vblank_def,
18423d0407baSopenharmony_ci				OV13855_VTS_MAX - mode->height,
18433d0407baSopenharmony_ci				1, vblank_def);
18443d0407baSopenharmony_ci
18453d0407baSopenharmony_ci	exposure_max = mode->vts_def - 4;
18463d0407baSopenharmony_ci	ov13855->exposure = v4l2_ctrl_new_std(handler, &ov13855_ctrl_ops,
18473d0407baSopenharmony_ci				V4L2_CID_EXPOSURE, OV13855_EXPOSURE_MIN,
18483d0407baSopenharmony_ci				exposure_max, OV13855_EXPOSURE_STEP,
18493d0407baSopenharmony_ci				mode->exp_def);
18503d0407baSopenharmony_ci
18513d0407baSopenharmony_ci	ov13855->anal_gain = v4l2_ctrl_new_std(handler, &ov13855_ctrl_ops,
18523d0407baSopenharmony_ci				V4L2_CID_ANALOGUE_GAIN, OV13855_GAIN_MIN,
18533d0407baSopenharmony_ci				OV13855_GAIN_MAX, OV13855_GAIN_STEP,
18543d0407baSopenharmony_ci				OV13855_GAIN_DEFAULT);
18553d0407baSopenharmony_ci
18563d0407baSopenharmony_ci	ov13855->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
18573d0407baSopenharmony_ci				&ov13855_ctrl_ops, V4L2_CID_TEST_PATTERN,
18583d0407baSopenharmony_ci				ARRAY_SIZE(ov13855_test_pattern_menu) - 1,
18593d0407baSopenharmony_ci				0, 0, ov13855_test_pattern_menu);
18603d0407baSopenharmony_ci
18613d0407baSopenharmony_ci	if (handler->error) {
18623d0407baSopenharmony_ci		ret = handler->error;
18633d0407baSopenharmony_ci		dev_err(&ov13855->client->dev,
18643d0407baSopenharmony_ci			"Failed to init controls(%d)\n", ret);
18653d0407baSopenharmony_ci		goto err_free_handler;
18663d0407baSopenharmony_ci	}
18673d0407baSopenharmony_ci
18683d0407baSopenharmony_ci	ov13855->subdev.ctrl_handler = handler;
18693d0407baSopenharmony_ci
18703d0407baSopenharmony_ci	return 0;
18713d0407baSopenharmony_ci
18723d0407baSopenharmony_cierr_free_handler:
18733d0407baSopenharmony_ci	v4l2_ctrl_handler_free(handler);
18743d0407baSopenharmony_ci
18753d0407baSopenharmony_ci	return ret;
18763d0407baSopenharmony_ci}
18773d0407baSopenharmony_ci
18783d0407baSopenharmony_cistatic int ov13855_check_sensor_id(struct ov13855 *ov13855,
18793d0407baSopenharmony_ci				   struct i2c_client *client)
18803d0407baSopenharmony_ci{
18813d0407baSopenharmony_ci	struct device *dev = &ov13855->client->dev;
18823d0407baSopenharmony_ci	u32 id = 0;
18833d0407baSopenharmony_ci	int ret;
18843d0407baSopenharmony_ci
18853d0407baSopenharmony_ci	ret = ov13855_read_reg(client, OV13855_REG_CHIP_ID,
18863d0407baSopenharmony_ci			       OV13855_REG_VALUE_24BIT, &id);
18873d0407baSopenharmony_ci	if (id != CHIP_ID) {
18883d0407baSopenharmony_ci		dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
18893d0407baSopenharmony_ci		return -ENODEV;
18903d0407baSopenharmony_ci	}
18913d0407baSopenharmony_ci
18923d0407baSopenharmony_ci	ret = ov13855_read_reg(client, OV13855_CHIP_REVISION_REG,
18933d0407baSopenharmony_ci			       OV13855_REG_VALUE_08BIT, &id);
18943d0407baSopenharmony_ci	if (ret) {
18953d0407baSopenharmony_ci		dev_err(dev, "Read chip revision register error\n");
18963d0407baSopenharmony_ci		return ret;
18973d0407baSopenharmony_ci	}
18983d0407baSopenharmony_ci
18993d0407baSopenharmony_ci	dev_info(dev, "Detected OV%06x sensor, REVISION 0x%x\n", CHIP_ID, id);
19003d0407baSopenharmony_ci
19013d0407baSopenharmony_ci	return 0;
19023d0407baSopenharmony_ci}
19033d0407baSopenharmony_ci
19043d0407baSopenharmony_cistatic int ov13855_configure_regulators(struct ov13855 *ov13855)
19053d0407baSopenharmony_ci{
19063d0407baSopenharmony_ci	unsigned int i;
19073d0407baSopenharmony_ci
19083d0407baSopenharmony_ci	for (i = 0; i < OV13855_NUM_SUPPLIES; i++)
19093d0407baSopenharmony_ci		ov13855->supplies[i].supply = ov13855_supply_names[i];
19103d0407baSopenharmony_ci
19113d0407baSopenharmony_ci	return devm_regulator_bulk_get(&ov13855->client->dev,
19123d0407baSopenharmony_ci				       OV13855_NUM_SUPPLIES,
19133d0407baSopenharmony_ci				       ov13855->supplies);
19143d0407baSopenharmony_ci}
19153d0407baSopenharmony_ci
19163d0407baSopenharmony_cistatic int ov13855_probe(struct i2c_client *client,
19173d0407baSopenharmony_ci			 const struct i2c_device_id *id)
19183d0407baSopenharmony_ci{
19193d0407baSopenharmony_ci	struct device *dev = &client->dev;
19203d0407baSopenharmony_ci	struct device_node *node = dev->of_node;
19213d0407baSopenharmony_ci	struct ov13855 *ov13855;
19223d0407baSopenharmony_ci	struct v4l2_subdev *sd;
19233d0407baSopenharmony_ci	char facing[2];
19243d0407baSopenharmony_ci	int ret;
19253d0407baSopenharmony_ci
19263d0407baSopenharmony_ci	dev_info(dev, "driver version: %02x.%02x.%02x",
19273d0407baSopenharmony_ci		DRIVER_VERSION >> 16,
19283d0407baSopenharmony_ci		(DRIVER_VERSION & 0xff00) >> 8,
19293d0407baSopenharmony_ci		DRIVER_VERSION & 0x00ff);
19303d0407baSopenharmony_ci
19313d0407baSopenharmony_ci	ov13855 = devm_kzalloc(dev, sizeof(*ov13855), GFP_KERNEL);
19323d0407baSopenharmony_ci	if (!ov13855)
19333d0407baSopenharmony_ci		return -ENOMEM;
19343d0407baSopenharmony_ci
19353d0407baSopenharmony_ci	ret = of_property_read_u32(node, RKMODULE_CAMERA_MODULE_INDEX,
19363d0407baSopenharmony_ci				   &ov13855->module_index);
19373d0407baSopenharmony_ci	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_FACING,
19383d0407baSopenharmony_ci				       &ov13855->module_facing);
19393d0407baSopenharmony_ci	ret |= of_property_read_string(node, RKMODULE_CAMERA_MODULE_NAME,
19403d0407baSopenharmony_ci				       &ov13855->module_name);
19413d0407baSopenharmony_ci	ret |= of_property_read_string(node, RKMODULE_CAMERA_LENS_NAME,
19423d0407baSopenharmony_ci				       &ov13855->len_name);
19433d0407baSopenharmony_ci	if (ret) {
19443d0407baSopenharmony_ci		dev_err(dev, "could not get module information!\n");
19453d0407baSopenharmony_ci		return -EINVAL;
19463d0407baSopenharmony_ci	}
19473d0407baSopenharmony_ci
19483d0407baSopenharmony_ci	ov13855->client = client;
19493d0407baSopenharmony_ci	ov13855->cur_mode = &supported_modes[0];
19503d0407baSopenharmony_ci
19513d0407baSopenharmony_ci	ov13855->xvclk = devm_clk_get(dev, "xvclk");
19523d0407baSopenharmony_ci	if (IS_ERR(ov13855->xvclk)) {
19533d0407baSopenharmony_ci		dev_err(dev, "Failed to get xvclk\n");
19543d0407baSopenharmony_ci		return -EINVAL;
19553d0407baSopenharmony_ci	}
19563d0407baSopenharmony_ci
19573d0407baSopenharmony_ci	ov13855->power_gpio = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
19583d0407baSopenharmony_ci	if (IS_ERR(ov13855->power_gpio))
19593d0407baSopenharmony_ci		dev_warn(dev, "Failed to get power-gpios, maybe no use\n");
19603d0407baSopenharmony_ci
19613d0407baSopenharmony_ci	ov13855->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
19623d0407baSopenharmony_ci	if (IS_ERR(ov13855->reset_gpio))
19633d0407baSopenharmony_ci		dev_warn(dev, "Failed to get reset-gpios\n");
19643d0407baSopenharmony_ci
19653d0407baSopenharmony_ci	ov13855->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
19663d0407baSopenharmony_ci	if (IS_ERR(ov13855->pwdn_gpio))
19673d0407baSopenharmony_ci		dev_warn(dev, "Failed to get pwdn-gpios\n");
19683d0407baSopenharmony_ci
19693d0407baSopenharmony_ci	ret = ov13855_configure_regulators(ov13855);
19703d0407baSopenharmony_ci	if (ret) {
19713d0407baSopenharmony_ci		dev_err(dev, "Failed to get power regulators\n");
19723d0407baSopenharmony_ci		return ret;
19733d0407baSopenharmony_ci	}
19743d0407baSopenharmony_ci
19753d0407baSopenharmony_ci	ov13855->pinctrl = devm_pinctrl_get(dev);
19763d0407baSopenharmony_ci	if (!IS_ERR(ov13855->pinctrl)) {
19773d0407baSopenharmony_ci		ov13855->pins_default =
19783d0407baSopenharmony_ci			pinctrl_lookup_state(ov13855->pinctrl,
19793d0407baSopenharmony_ci					     OF_CAMERA_PINCTRL_STATE_DEFAULT);
19803d0407baSopenharmony_ci		if (IS_ERR(ov13855->pins_default))
19813d0407baSopenharmony_ci			dev_err(dev, "could not get default pinstate\n");
19823d0407baSopenharmony_ci
19833d0407baSopenharmony_ci		ov13855->pins_sleep =
19843d0407baSopenharmony_ci			pinctrl_lookup_state(ov13855->pinctrl,
19853d0407baSopenharmony_ci					     OF_CAMERA_PINCTRL_STATE_SLEEP);
19863d0407baSopenharmony_ci		if (IS_ERR(ov13855->pins_sleep))
19873d0407baSopenharmony_ci			dev_err(dev, "could not get sleep pinstate\n");
19883d0407baSopenharmony_ci	}
19893d0407baSopenharmony_ci
19903d0407baSopenharmony_ci	mutex_init(&ov13855->mutex);
19913d0407baSopenharmony_ci
19923d0407baSopenharmony_ci	sd = &ov13855->subdev;
19933d0407baSopenharmony_ci	v4l2_i2c_subdev_init(sd, client, &ov13855_subdev_ops);
19943d0407baSopenharmony_ci	ret = ov13855_initialize_controls(ov13855);
19953d0407baSopenharmony_ci	if (ret)
19963d0407baSopenharmony_ci		goto err_destroy_mutex;
19973d0407baSopenharmony_ci
19983d0407baSopenharmony_ci	ret = __ov13855_power_on(ov13855);
19993d0407baSopenharmony_ci	if (ret)
20003d0407baSopenharmony_ci		goto err_free_handler;
20013d0407baSopenharmony_ci
20023d0407baSopenharmony_ci	ret = ov13855_check_sensor_id(ov13855, client);
20033d0407baSopenharmony_ci	if (ret)
20043d0407baSopenharmony_ci		goto err_power_off;
20053d0407baSopenharmony_ci
20063d0407baSopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
20073d0407baSopenharmony_ci	sd->internal_ops = &ov13855_internal_ops;
20083d0407baSopenharmony_ci	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
20093d0407baSopenharmony_ci#endif
20103d0407baSopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
20113d0407baSopenharmony_ci	ov13855->pad.flags = MEDIA_PAD_FL_SOURCE;
20123d0407baSopenharmony_ci	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
20133d0407baSopenharmony_ci	ret = media_entity_pads_init(&sd->entity, 1, &ov13855->pad);
20143d0407baSopenharmony_ci	if (ret < 0)
20153d0407baSopenharmony_ci		goto err_power_off;
20163d0407baSopenharmony_ci#endif
20173d0407baSopenharmony_ci
20183d0407baSopenharmony_ci	memset(facing, 0, sizeof(facing));
20193d0407baSopenharmony_ci	if (strcmp(ov13855->module_facing, "back") == 0)
20203d0407baSopenharmony_ci		facing[0] = 'b';
20213d0407baSopenharmony_ci	else
20223d0407baSopenharmony_ci		facing[0] = 'f';
20233d0407baSopenharmony_ci
20243d0407baSopenharmony_ci	snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s",
20253d0407baSopenharmony_ci		 ov13855->module_index, facing,
20263d0407baSopenharmony_ci		 OV13855_NAME, dev_name(sd->dev));
20273d0407baSopenharmony_ci	ret = v4l2_async_register_subdev_sensor_common(sd);
20283d0407baSopenharmony_ci	if (ret) {
20293d0407baSopenharmony_ci		dev_err(dev, "v4l2 async register subdev failed\n");
20303d0407baSopenharmony_ci		goto err_clean_entity;
20313d0407baSopenharmony_ci	}
20323d0407baSopenharmony_ci
20333d0407baSopenharmony_ci	pm_runtime_set_active(dev);
20343d0407baSopenharmony_ci	pm_runtime_enable(dev);
20353d0407baSopenharmony_ci	pm_runtime_idle(dev);
20363d0407baSopenharmony_ci
20373d0407baSopenharmony_ci	return 0;
20383d0407baSopenharmony_ci
20393d0407baSopenharmony_cierr_clean_entity:
20403d0407baSopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
20413d0407baSopenharmony_ci	media_entity_cleanup(&sd->entity);
20423d0407baSopenharmony_ci#endif
20433d0407baSopenharmony_cierr_power_off:
20443d0407baSopenharmony_ci	__ov13855_power_off(ov13855);
20453d0407baSopenharmony_cierr_free_handler:
20463d0407baSopenharmony_ci	v4l2_ctrl_handler_free(&ov13855->ctrl_handler);
20473d0407baSopenharmony_cierr_destroy_mutex:
20483d0407baSopenharmony_ci	mutex_destroy(&ov13855->mutex);
20493d0407baSopenharmony_ci
20503d0407baSopenharmony_ci	return ret;
20513d0407baSopenharmony_ci}
20523d0407baSopenharmony_ci
20533d0407baSopenharmony_cistatic int ov13855_remove(struct i2c_client *client)
20543d0407baSopenharmony_ci{
20553d0407baSopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
20563d0407baSopenharmony_ci	struct ov13855 *ov13855 = to_ov13855(sd);
20573d0407baSopenharmony_ci
20583d0407baSopenharmony_ci	v4l2_async_unregister_subdev(sd);
20593d0407baSopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
20603d0407baSopenharmony_ci	media_entity_cleanup(&sd->entity);
20613d0407baSopenharmony_ci#endif
20623d0407baSopenharmony_ci	v4l2_ctrl_handler_free(&ov13855->ctrl_handler);
20633d0407baSopenharmony_ci	mutex_destroy(&ov13855->mutex);
20643d0407baSopenharmony_ci
20653d0407baSopenharmony_ci	pm_runtime_disable(&client->dev);
20663d0407baSopenharmony_ci	if (!pm_runtime_status_suspended(&client->dev))
20673d0407baSopenharmony_ci		__ov13855_power_off(ov13855);
20683d0407baSopenharmony_ci	pm_runtime_set_suspended(&client->dev);
20693d0407baSopenharmony_ci
20703d0407baSopenharmony_ci	return 0;
20713d0407baSopenharmony_ci}
20723d0407baSopenharmony_ci
20733d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_OF)
20743d0407baSopenharmony_cistatic const struct of_device_id ov13855_of_match[] = {
20753d0407baSopenharmony_ci	{ .compatible = "ovti,ov13855" },
20763d0407baSopenharmony_ci	{},
20773d0407baSopenharmony_ci};
20783d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, ov13855_of_match);
20793d0407baSopenharmony_ci#endif
20803d0407baSopenharmony_ci
20813d0407baSopenharmony_cistatic const struct i2c_device_id ov13855_match_id[] = {
20823d0407baSopenharmony_ci	{ "ovti,ov13855", 0 },
20833d0407baSopenharmony_ci	{},
20843d0407baSopenharmony_ci};
20853d0407baSopenharmony_ci
20863d0407baSopenharmony_cistatic struct i2c_driver ov13855_i2c_driver = {
20873d0407baSopenharmony_ci	.driver = {
20883d0407baSopenharmony_ci		.name = OV13855_NAME,
20893d0407baSopenharmony_ci		.pm = &ov13855_pm_ops,
20903d0407baSopenharmony_ci		.of_match_table = of_match_ptr(ov13855_of_match),
20913d0407baSopenharmony_ci	},
20923d0407baSopenharmony_ci	.probe		= &ov13855_probe,
20933d0407baSopenharmony_ci	.remove		= &ov13855_remove,
20943d0407baSopenharmony_ci	.id_table	= ov13855_match_id,
20953d0407baSopenharmony_ci};
20963d0407baSopenharmony_ci
20973d0407baSopenharmony_cistatic int __init sensor_mod_init(void)
20983d0407baSopenharmony_ci{
20993d0407baSopenharmony_ci	return i2c_add_driver(&ov13855_i2c_driver);
21003d0407baSopenharmony_ci}
21013d0407baSopenharmony_ci
21023d0407baSopenharmony_cistatic void __exit sensor_mod_exit(void)
21033d0407baSopenharmony_ci{
21043d0407baSopenharmony_ci	i2c_del_driver(&ov13855_i2c_driver);
21053d0407baSopenharmony_ci}
21063d0407baSopenharmony_ci
21073d0407baSopenharmony_cidevice_initcall_sync(sensor_mod_init);
21083d0407baSopenharmony_cimodule_exit(sensor_mod_exit);
21093d0407baSopenharmony_ci
21103d0407baSopenharmony_ciMODULE_DESCRIPTION("OmniVision ov13855 sensor driver");
21113d0407baSopenharmony_ciMODULE_LICENSE("GPL v2");
2112