xref: /openbmc/linux/drivers/media/i2c/ov5695.c (revision aaeb31c0)
18a77009bSShunqian Zheng // SPDX-License-Identifier: GPL-2.0
28a77009bSShunqian Zheng /*
38a77009bSShunqian Zheng  * ov5695 driver
48a77009bSShunqian Zheng  *
58a77009bSShunqian Zheng  * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
68a77009bSShunqian Zheng  */
78a77009bSShunqian Zheng 
88a77009bSShunqian Zheng #include <linux/clk.h>
98a77009bSShunqian Zheng #include <linux/device.h>
108a77009bSShunqian Zheng #include <linux/delay.h>
118a77009bSShunqian Zheng #include <linux/gpio/consumer.h>
128a77009bSShunqian Zheng #include <linux/i2c.h>
138a77009bSShunqian Zheng #include <linux/module.h>
148a77009bSShunqian Zheng #include <linux/pm_runtime.h>
158a77009bSShunqian Zheng #include <linux/regulator/consumer.h>
168a77009bSShunqian Zheng #include <linux/sysfs.h>
178a77009bSShunqian Zheng #include <media/media-entity.h>
188a77009bSShunqian Zheng #include <media/v4l2-async.h>
198a77009bSShunqian Zheng #include <media/v4l2-ctrls.h>
208a77009bSShunqian Zheng #include <media/v4l2-subdev.h>
218a77009bSShunqian Zheng 
228a77009bSShunqian Zheng #ifndef V4L2_CID_DIGITAL_GAIN
238a77009bSShunqian Zheng #define V4L2_CID_DIGITAL_GAIN		V4L2_CID_GAIN
248a77009bSShunqian Zheng #endif
258a77009bSShunqian Zheng 
268a77009bSShunqian Zheng /* 45Mhz * 4 Binning */
278a77009bSShunqian Zheng #define OV5695_PIXEL_RATE		(45 * 1000 * 1000 * 4)
288a77009bSShunqian Zheng #define OV5695_XVCLK_FREQ		24000000
298a77009bSShunqian Zheng 
308a77009bSShunqian Zheng #define CHIP_ID				0x005695
318a77009bSShunqian Zheng #define OV5695_REG_CHIP_ID		0x300a
328a77009bSShunqian Zheng 
338a77009bSShunqian Zheng #define OV5695_REG_CTRL_MODE		0x0100
348a77009bSShunqian Zheng #define OV5695_MODE_SW_STANDBY		0x0
358a77009bSShunqian Zheng #define OV5695_MODE_STREAMING		BIT(0)
368a77009bSShunqian Zheng 
378a77009bSShunqian Zheng #define OV5695_REG_EXPOSURE		0x3500
388a77009bSShunqian Zheng #define	OV5695_EXPOSURE_MIN		4
398a77009bSShunqian Zheng #define	OV5695_EXPOSURE_STEP		1
408a77009bSShunqian Zheng #define OV5695_VTS_MAX			0x7fff
418a77009bSShunqian Zheng 
428a77009bSShunqian Zheng #define OV5695_REG_ANALOG_GAIN		0x3509
438a77009bSShunqian Zheng #define	ANALOG_GAIN_MIN			0x10
448a77009bSShunqian Zheng #define	ANALOG_GAIN_MAX			0xf8
458a77009bSShunqian Zheng #define	ANALOG_GAIN_STEP		1
468a77009bSShunqian Zheng #define	ANALOG_GAIN_DEFAULT		0xf8
478a77009bSShunqian Zheng 
488a77009bSShunqian Zheng #define OV5695_REG_DIGI_GAIN_H		0x350a
498a77009bSShunqian Zheng #define OV5695_REG_DIGI_GAIN_L		0x350b
508a77009bSShunqian Zheng #define OV5695_DIGI_GAIN_L_MASK		0x3f
518a77009bSShunqian Zheng #define OV5695_DIGI_GAIN_H_SHIFT	6
528a77009bSShunqian Zheng #define OV5695_DIGI_GAIN_MIN		0
538a77009bSShunqian Zheng #define OV5695_DIGI_GAIN_MAX		(0x4000 - 1)
548a77009bSShunqian Zheng #define OV5695_DIGI_GAIN_STEP		1
558a77009bSShunqian Zheng #define OV5695_DIGI_GAIN_DEFAULT	1024
568a77009bSShunqian Zheng 
578a77009bSShunqian Zheng #define OV5695_REG_TEST_PATTERN		0x4503
588a77009bSShunqian Zheng #define	OV5695_TEST_PATTERN_ENABLE	0x80
598a77009bSShunqian Zheng #define	OV5695_TEST_PATTERN_DISABLE	0x0
608a77009bSShunqian Zheng 
618a77009bSShunqian Zheng #define OV5695_REG_VTS			0x380e
628a77009bSShunqian Zheng 
638a77009bSShunqian Zheng #define REG_NULL			0xFFFF
648a77009bSShunqian Zheng 
658a77009bSShunqian Zheng #define OV5695_REG_VALUE_08BIT		1
668a77009bSShunqian Zheng #define OV5695_REG_VALUE_16BIT		2
678a77009bSShunqian Zheng #define OV5695_REG_VALUE_24BIT		3
688a77009bSShunqian Zheng 
698a77009bSShunqian Zheng #define OV5695_LANES			2
708a77009bSShunqian Zheng #define OV5695_BITS_PER_SAMPLE		10
718a77009bSShunqian Zheng 
728a77009bSShunqian Zheng static const char * const ov5695_supply_names[] = {
738a77009bSShunqian Zheng 	"avdd",		/* Analog power */
748a77009bSShunqian Zheng 	"dovdd",	/* Digital I/O power */
758a77009bSShunqian Zheng 	"dvdd",		/* Digital core power */
768a77009bSShunqian Zheng };
778a77009bSShunqian Zheng 
788a77009bSShunqian Zheng #define OV5695_NUM_SUPPLIES ARRAY_SIZE(ov5695_supply_names)
798a77009bSShunqian Zheng 
808a77009bSShunqian Zheng struct regval {
818a77009bSShunqian Zheng 	u16 addr;
828a77009bSShunqian Zheng 	u8 val;
838a77009bSShunqian Zheng };
848a77009bSShunqian Zheng 
858a77009bSShunqian Zheng struct ov5695_mode {
868a77009bSShunqian Zheng 	u32 width;
878a77009bSShunqian Zheng 	u32 height;
888a77009bSShunqian Zheng 	u32 max_fps;
898a77009bSShunqian Zheng 	u32 hts_def;
908a77009bSShunqian Zheng 	u32 vts_def;
918a77009bSShunqian Zheng 	u32 exp_def;
928a77009bSShunqian Zheng 	const struct regval *reg_list;
938a77009bSShunqian Zheng };
948a77009bSShunqian Zheng 
958a77009bSShunqian Zheng struct ov5695 {
968a77009bSShunqian Zheng 	struct i2c_client	*client;
978a77009bSShunqian Zheng 	struct clk		*xvclk;
988a77009bSShunqian Zheng 	struct gpio_desc	*reset_gpio;
998a77009bSShunqian Zheng 	struct regulator_bulk_data supplies[OV5695_NUM_SUPPLIES];
1008a77009bSShunqian Zheng 
1018a77009bSShunqian Zheng 	struct v4l2_subdev	subdev;
1028a77009bSShunqian Zheng 	struct media_pad	pad;
1038a77009bSShunqian Zheng 	struct v4l2_ctrl_handler ctrl_handler;
1048a77009bSShunqian Zheng 	struct v4l2_ctrl	*exposure;
1058a77009bSShunqian Zheng 	struct v4l2_ctrl	*anal_gain;
1068a77009bSShunqian Zheng 	struct v4l2_ctrl	*digi_gain;
1078a77009bSShunqian Zheng 	struct v4l2_ctrl	*hblank;
1088a77009bSShunqian Zheng 	struct v4l2_ctrl	*vblank;
1098a77009bSShunqian Zheng 	struct v4l2_ctrl	*test_pattern;
1108a77009bSShunqian Zheng 	struct mutex		mutex;
1118a77009bSShunqian Zheng 	bool			streaming;
1128a77009bSShunqian Zheng 	const struct ov5695_mode *cur_mode;
1138a77009bSShunqian Zheng };
1148a77009bSShunqian Zheng 
1158a77009bSShunqian Zheng #define to_ov5695(sd) container_of(sd, struct ov5695, subdev)
1168a77009bSShunqian Zheng 
1178a77009bSShunqian Zheng /*
1188a77009bSShunqian Zheng  * Xclk 24Mhz
1198a77009bSShunqian Zheng  * Pclk 45Mhz
1208a77009bSShunqian Zheng  * linelength 672(0x2a0)
1218a77009bSShunqian Zheng  * framelength 2232(0x8b8)
1228a77009bSShunqian Zheng  * grabwindow_width 1296
1238a77009bSShunqian Zheng  * grabwindow_height 972
1248a77009bSShunqian Zheng  * max_framerate 30fps
1258a77009bSShunqian Zheng  * mipi_datarate per lane 840Mbps
1268a77009bSShunqian Zheng  */
1278a77009bSShunqian Zheng static const struct regval ov5695_global_regs[] = {
1288a77009bSShunqian Zheng 	{0x0103, 0x01},
1298a77009bSShunqian Zheng 	{0x0100, 0x00},
1308a77009bSShunqian Zheng 	{0x0300, 0x04},
1318a77009bSShunqian Zheng 	{0x0301, 0x00},
1328a77009bSShunqian Zheng 	{0x0302, 0x69},
1338a77009bSShunqian Zheng 	{0x0303, 0x00},
1348a77009bSShunqian Zheng 	{0x0304, 0x00},
1358a77009bSShunqian Zheng 	{0x0305, 0x01},
1368a77009bSShunqian Zheng 	{0x0307, 0x00},
1378a77009bSShunqian Zheng 	{0x030b, 0x00},
1388a77009bSShunqian Zheng 	{0x030c, 0x00},
1398a77009bSShunqian Zheng 	{0x030d, 0x1e},
1408a77009bSShunqian Zheng 	{0x030e, 0x04},
1418a77009bSShunqian Zheng 	{0x030f, 0x03},
1428a77009bSShunqian Zheng 	{0x0312, 0x01},
1438a77009bSShunqian Zheng 	{0x3000, 0x00},
1448a77009bSShunqian Zheng 	{0x3002, 0xa1},
1458a77009bSShunqian Zheng 	{0x3008, 0x00},
1468a77009bSShunqian Zheng 	{0x3010, 0x00},
1478a77009bSShunqian Zheng 	{0x3022, 0x51},
1488a77009bSShunqian Zheng 	{0x3106, 0x15},
1498a77009bSShunqian Zheng 	{0x3107, 0x01},
1508a77009bSShunqian Zheng 	{0x3108, 0x05},
1518a77009bSShunqian Zheng 	{0x3500, 0x00},
1528a77009bSShunqian Zheng 	{0x3501, 0x45},
1538a77009bSShunqian Zheng 	{0x3502, 0x00},
1548a77009bSShunqian Zheng 	{0x3503, 0x08},
1558a77009bSShunqian Zheng 	{0x3504, 0x03},
1568a77009bSShunqian Zheng 	{0x3505, 0x8c},
1578a77009bSShunqian Zheng 	{0x3507, 0x03},
1588a77009bSShunqian Zheng 	{0x3508, 0x00},
1598a77009bSShunqian Zheng 	{0x3509, 0x10},
1608a77009bSShunqian Zheng 	{0x350c, 0x00},
1618a77009bSShunqian Zheng 	{0x350d, 0x80},
1628a77009bSShunqian Zheng 	{0x3510, 0x00},
1638a77009bSShunqian Zheng 	{0x3511, 0x02},
1648a77009bSShunqian Zheng 	{0x3512, 0x00},
1658a77009bSShunqian Zheng 	{0x3601, 0x55},
1668a77009bSShunqian Zheng 	{0x3602, 0x58},
1678a77009bSShunqian Zheng 	{0x3614, 0x30},
1688a77009bSShunqian Zheng 	{0x3615, 0x77},
1698a77009bSShunqian Zheng 	{0x3621, 0x08},
1708a77009bSShunqian Zheng 	{0x3624, 0x40},
1718a77009bSShunqian Zheng 	{0x3633, 0x0c},
1728a77009bSShunqian Zheng 	{0x3634, 0x0c},
1738a77009bSShunqian Zheng 	{0x3635, 0x0c},
1748a77009bSShunqian Zheng 	{0x3636, 0x0c},
1758a77009bSShunqian Zheng 	{0x3638, 0x00},
1768a77009bSShunqian Zheng 	{0x3639, 0x00},
1778a77009bSShunqian Zheng 	{0x363a, 0x00},
1788a77009bSShunqian Zheng 	{0x363b, 0x00},
1798a77009bSShunqian Zheng 	{0x363c, 0xff},
1808a77009bSShunqian Zheng 	{0x363d, 0xfa},
1818a77009bSShunqian Zheng 	{0x3650, 0x44},
1828a77009bSShunqian Zheng 	{0x3651, 0x44},
1838a77009bSShunqian Zheng 	{0x3652, 0x44},
1848a77009bSShunqian Zheng 	{0x3653, 0x44},
1858a77009bSShunqian Zheng 	{0x3654, 0x44},
1868a77009bSShunqian Zheng 	{0x3655, 0x44},
1878a77009bSShunqian Zheng 	{0x3656, 0x44},
1888a77009bSShunqian Zheng 	{0x3657, 0x44},
1898a77009bSShunqian Zheng 	{0x3660, 0x00},
1908a77009bSShunqian Zheng 	{0x3661, 0x00},
1918a77009bSShunqian Zheng 	{0x3662, 0x00},
1928a77009bSShunqian Zheng 	{0x366a, 0x00},
1938a77009bSShunqian Zheng 	{0x366e, 0x0c},
1948a77009bSShunqian Zheng 	{0x3673, 0x04},
1958a77009bSShunqian Zheng 	{0x3700, 0x14},
1968a77009bSShunqian Zheng 	{0x3703, 0x0c},
1978a77009bSShunqian Zheng 	{0x3715, 0x01},
1988a77009bSShunqian Zheng 	{0x3733, 0x10},
1998a77009bSShunqian Zheng 	{0x3734, 0x40},
2008a77009bSShunqian Zheng 	{0x373f, 0xa0},
2018a77009bSShunqian Zheng 	{0x3765, 0x20},
2028a77009bSShunqian Zheng 	{0x37a1, 0x1d},
2038a77009bSShunqian Zheng 	{0x37a8, 0x26},
2048a77009bSShunqian Zheng 	{0x37ab, 0x14},
2058a77009bSShunqian Zheng 	{0x37c2, 0x04},
2068a77009bSShunqian Zheng 	{0x37cb, 0x09},
2078a77009bSShunqian Zheng 	{0x37cc, 0x13},
2088a77009bSShunqian Zheng 	{0x37cd, 0x1f},
2098a77009bSShunqian Zheng 	{0x37ce, 0x1f},
2108a77009bSShunqian Zheng 	{0x3800, 0x00},
2118a77009bSShunqian Zheng 	{0x3801, 0x00},
2128a77009bSShunqian Zheng 	{0x3802, 0x00},
2138a77009bSShunqian Zheng 	{0x3803, 0x00},
2148a77009bSShunqian Zheng 	{0x3804, 0x0a},
2158a77009bSShunqian Zheng 	{0x3805, 0x3f},
2168a77009bSShunqian Zheng 	{0x3806, 0x07},
2178a77009bSShunqian Zheng 	{0x3807, 0xaf},
2188a77009bSShunqian Zheng 	{0x3808, 0x05},
2198a77009bSShunqian Zheng 	{0x3809, 0x10},
2208a77009bSShunqian Zheng 	{0x380a, 0x03},
2218a77009bSShunqian Zheng 	{0x380b, 0xcc},
2228a77009bSShunqian Zheng 	{0x380c, 0x02},
2238a77009bSShunqian Zheng 	{0x380d, 0xa0},
2248a77009bSShunqian Zheng 	{0x380e, 0x08},
2258a77009bSShunqian Zheng 	{0x380f, 0xb8},
2268a77009bSShunqian Zheng 	{0x3810, 0x00},
2278a77009bSShunqian Zheng 	{0x3811, 0x06},
2288a77009bSShunqian Zheng 	{0x3812, 0x00},
2298a77009bSShunqian Zheng 	{0x3813, 0x06},
2308a77009bSShunqian Zheng 	{0x3814, 0x03},
2318a77009bSShunqian Zheng 	{0x3815, 0x01},
2328a77009bSShunqian Zheng 	{0x3816, 0x03},
2338a77009bSShunqian Zheng 	{0x3817, 0x01},
2348a77009bSShunqian Zheng 	{0x3818, 0x00},
2358a77009bSShunqian Zheng 	{0x3819, 0x00},
2368a77009bSShunqian Zheng 	{0x381a, 0x00},
2378a77009bSShunqian Zheng 	{0x381b, 0x01},
2388a77009bSShunqian Zheng 	{0x3820, 0x8b},
2398a77009bSShunqian Zheng 	{0x3821, 0x01},
2408a77009bSShunqian Zheng 	{0x3c80, 0x08},
2418a77009bSShunqian Zheng 	{0x3c82, 0x00},
2428a77009bSShunqian Zheng 	{0x3c83, 0x00},
2438a77009bSShunqian Zheng 	{0x3c88, 0x00},
2448a77009bSShunqian Zheng 	{0x3d85, 0x14},
2458a77009bSShunqian Zheng 	{0x3f02, 0x08},
2468a77009bSShunqian Zheng 	{0x3f03, 0x10},
2478a77009bSShunqian Zheng 	{0x4008, 0x02},
2488a77009bSShunqian Zheng 	{0x4009, 0x09},
2498a77009bSShunqian Zheng 	{0x404e, 0x20},
2508a77009bSShunqian Zheng 	{0x4501, 0x00},
2518a77009bSShunqian Zheng 	{0x4502, 0x10},
2528a77009bSShunqian Zheng 	{0x4800, 0x00},
2538a77009bSShunqian Zheng 	{0x481f, 0x2a},
2548a77009bSShunqian Zheng 	{0x4837, 0x13},
2558a77009bSShunqian Zheng 	{0x5000, 0x17},
2568a77009bSShunqian Zheng 	{0x5780, 0x3e},
2578a77009bSShunqian Zheng 	{0x5781, 0x0f},
2588a77009bSShunqian Zheng 	{0x5782, 0x44},
2598a77009bSShunqian Zheng 	{0x5783, 0x02},
2608a77009bSShunqian Zheng 	{0x5784, 0x01},
2618a77009bSShunqian Zheng 	{0x5785, 0x01},
2628a77009bSShunqian Zheng 	{0x5786, 0x00},
2638a77009bSShunqian Zheng 	{0x5787, 0x04},
2648a77009bSShunqian Zheng 	{0x5788, 0x02},
2658a77009bSShunqian Zheng 	{0x5789, 0x0f},
2668a77009bSShunqian Zheng 	{0x578a, 0xfd},
2678a77009bSShunqian Zheng 	{0x578b, 0xf5},
2688a77009bSShunqian Zheng 	{0x578c, 0xf5},
2698a77009bSShunqian Zheng 	{0x578d, 0x03},
2708a77009bSShunqian Zheng 	{0x578e, 0x08},
2718a77009bSShunqian Zheng 	{0x578f, 0x0c},
2728a77009bSShunqian Zheng 	{0x5790, 0x08},
2738a77009bSShunqian Zheng 	{0x5791, 0x06},
2748a77009bSShunqian Zheng 	{0x5792, 0x00},
2758a77009bSShunqian Zheng 	{0x5793, 0x52},
2768a77009bSShunqian Zheng 	{0x5794, 0xa3},
2778a77009bSShunqian Zheng 	{0x5b00, 0x00},
2788a77009bSShunqian Zheng 	{0x5b01, 0x1c},
2798a77009bSShunqian Zheng 	{0x5b02, 0x00},
2808a77009bSShunqian Zheng 	{0x5b03, 0x7f},
2818a77009bSShunqian Zheng 	{0x5b05, 0x6c},
2828a77009bSShunqian Zheng 	{0x5e10, 0xfc},
2838a77009bSShunqian Zheng 	{0x4010, 0xf1},
2848a77009bSShunqian Zheng 	{0x3503, 0x08},
2858a77009bSShunqian Zheng 	{0x3505, 0x8c},
2868a77009bSShunqian Zheng 	{0x3507, 0x03},
2878a77009bSShunqian Zheng 	{0x3508, 0x00},
2888a77009bSShunqian Zheng 	{0x3509, 0xf8},
2898a77009bSShunqian Zheng 	{REG_NULL, 0x00},
2908a77009bSShunqian Zheng };
2918a77009bSShunqian Zheng 
2928a77009bSShunqian Zheng /*
2938a77009bSShunqian Zheng  * Xclk 24Mhz
2948a77009bSShunqian Zheng  * Pclk 45Mhz
2958a77009bSShunqian Zheng  * linelength 740(0x2e4)
2968a77009bSShunqian Zheng  * framelength 2024(0x7e8)
2978a77009bSShunqian Zheng  * grabwindow_width 2592
2988a77009bSShunqian Zheng  * grabwindow_height 1944
2998a77009bSShunqian Zheng  * max_framerate 30fps
3008a77009bSShunqian Zheng  * mipi_datarate per lane 840Mbps
3018a77009bSShunqian Zheng  */
3028a77009bSShunqian Zheng static const struct regval ov5695_2592x1944_regs[] = {
3038a77009bSShunqian Zheng 	{0x3501, 0x7e},
3048a77009bSShunqian Zheng 	{0x366e, 0x18},
3058a77009bSShunqian Zheng 	{0x3800, 0x00},
3068a77009bSShunqian Zheng 	{0x3801, 0x00},
3078a77009bSShunqian Zheng 	{0x3802, 0x00},
3088a77009bSShunqian Zheng 	{0x3803, 0x04},
3098a77009bSShunqian Zheng 	{0x3804, 0x0a},
3108a77009bSShunqian Zheng 	{0x3805, 0x3f},
3118a77009bSShunqian Zheng 	{0x3806, 0x07},
3128a77009bSShunqian Zheng 	{0x3807, 0xab},
3138a77009bSShunqian Zheng 	{0x3808, 0x0a},
3148a77009bSShunqian Zheng 	{0x3809, 0x20},
3158a77009bSShunqian Zheng 	{0x380a, 0x07},
3168a77009bSShunqian Zheng 	{0x380b, 0x98},
3178a77009bSShunqian Zheng 	{0x380c, 0x02},
3188a77009bSShunqian Zheng 	{0x380d, 0xe4},
3198a77009bSShunqian Zheng 	{0x380e, 0x07},
3208a77009bSShunqian Zheng 	{0x380f, 0xe8},
3218a77009bSShunqian Zheng 	{0x3811, 0x06},
3228a77009bSShunqian Zheng 	{0x3813, 0x08},
3238a77009bSShunqian Zheng 	{0x3814, 0x01},
3248a77009bSShunqian Zheng 	{0x3816, 0x01},
3258a77009bSShunqian Zheng 	{0x3817, 0x01},
3268a77009bSShunqian Zheng 	{0x3820, 0x88},
3278a77009bSShunqian Zheng 	{0x3821, 0x00},
3288a77009bSShunqian Zheng 	{0x4501, 0x00},
3298a77009bSShunqian Zheng 	{0x4008, 0x04},
3308a77009bSShunqian Zheng 	{0x4009, 0x13},
3318a77009bSShunqian Zheng 	{REG_NULL, 0x00},
3328a77009bSShunqian Zheng };
3338a77009bSShunqian Zheng 
3348a77009bSShunqian Zheng /*
3358a77009bSShunqian Zheng  * Xclk 24Mhz
3368a77009bSShunqian Zheng  * Pclk 45Mhz
3378a77009bSShunqian Zheng  * linelength 672(0x2a0)
3388a77009bSShunqian Zheng  * framelength 2232(0x8b8)
3398a77009bSShunqian Zheng  * grabwindow_width 1920
3408a77009bSShunqian Zheng  * grabwindow_height 1080
3418a77009bSShunqian Zheng  * max_framerate 30fps
3428a77009bSShunqian Zheng  * mipi_datarate per lane 840Mbps
3438a77009bSShunqian Zheng  */
3448a77009bSShunqian Zheng static const struct regval ov5695_1920x1080_regs[] = {
3458a77009bSShunqian Zheng 	{0x3501, 0x45},
3468a77009bSShunqian Zheng 	{0x366e, 0x18},
3478a77009bSShunqian Zheng 	{0x3800, 0x01},
3488a77009bSShunqian Zheng 	{0x3801, 0x50},
3498a77009bSShunqian Zheng 	{0x3802, 0x01},
3508a77009bSShunqian Zheng 	{0x3803, 0xb8},
3518a77009bSShunqian Zheng 	{0x3804, 0x08},
3528a77009bSShunqian Zheng 	{0x3805, 0xef},
3538a77009bSShunqian Zheng 	{0x3806, 0x05},
3548a77009bSShunqian Zheng 	{0x3807, 0xf7},
3558a77009bSShunqian Zheng 	{0x3808, 0x07},
3568a77009bSShunqian Zheng 	{0x3809, 0x80},
3578a77009bSShunqian Zheng 	{0x380a, 0x04},
3588a77009bSShunqian Zheng 	{0x380b, 0x38},
3598a77009bSShunqian Zheng 	{0x380c, 0x02},
3608a77009bSShunqian Zheng 	{0x380d, 0xa0},
3618a77009bSShunqian Zheng 	{0x380e, 0x08},
3628a77009bSShunqian Zheng 	{0x380f, 0xb8},
3638a77009bSShunqian Zheng 	{0x3811, 0x06},
3648a77009bSShunqian Zheng 	{0x3813, 0x04},
3658a77009bSShunqian Zheng 	{0x3814, 0x01},
3668a77009bSShunqian Zheng 	{0x3816, 0x01},
3678a77009bSShunqian Zheng 	{0x3817, 0x01},
3688a77009bSShunqian Zheng 	{0x3820, 0x88},
3698a77009bSShunqian Zheng 	{0x3821, 0x00},
3708a77009bSShunqian Zheng 	{0x4501, 0x00},
3718a77009bSShunqian Zheng 	{0x4008, 0x04},
3728a77009bSShunqian Zheng 	{0x4009, 0x13},
3738a77009bSShunqian Zheng 	{REG_NULL, 0x00}
3748a77009bSShunqian Zheng };
3758a77009bSShunqian Zheng 
3768a77009bSShunqian Zheng /*
3778a77009bSShunqian Zheng  * Xclk 24Mhz
3788a77009bSShunqian Zheng  * Pclk 45Mhz
3798a77009bSShunqian Zheng  * linelength 740(0x02e4)
3808a77009bSShunqian Zheng  * framelength 1012(0x03f4)
3818a77009bSShunqian Zheng  * grabwindow_width 1296
3828a77009bSShunqian Zheng  * grabwindow_height 972
3838a77009bSShunqian Zheng  * max_framerate 60fps
3848a77009bSShunqian Zheng  * mipi_datarate per lane 840Mbps
3858a77009bSShunqian Zheng  */
3868a77009bSShunqian Zheng static const struct regval ov5695_1296x972_regs[] = {
3878a77009bSShunqian Zheng 	{0x0103, 0x01},
3888a77009bSShunqian Zheng 	{0x0100, 0x00},
3898a77009bSShunqian Zheng 	{0x0300, 0x04},
3908a77009bSShunqian Zheng 	{0x0301, 0x00},
3918a77009bSShunqian Zheng 	{0x0302, 0x69},
3928a77009bSShunqian Zheng 	{0x0303, 0x00},
3938a77009bSShunqian Zheng 	{0x0304, 0x00},
3948a77009bSShunqian Zheng 	{0x0305, 0x01},
3958a77009bSShunqian Zheng 	{0x0307, 0x00},
3968a77009bSShunqian Zheng 	{0x030b, 0x00},
3978a77009bSShunqian Zheng 	{0x030c, 0x00},
3988a77009bSShunqian Zheng 	{0x030d, 0x1e},
3998a77009bSShunqian Zheng 	{0x030e, 0x04},
4008a77009bSShunqian Zheng 	{0x030f, 0x03},
4018a77009bSShunqian Zheng 	{0x0312, 0x01},
4028a77009bSShunqian Zheng 	{0x3000, 0x00},
4038a77009bSShunqian Zheng 	{0x3002, 0xa1},
4048a77009bSShunqian Zheng 	{0x3008, 0x00},
4058a77009bSShunqian Zheng 	{0x3010, 0x00},
4068a77009bSShunqian Zheng 	{0x3016, 0x32},
4078a77009bSShunqian Zheng 	{0x3022, 0x51},
4088a77009bSShunqian Zheng 	{0x3106, 0x15},
4098a77009bSShunqian Zheng 	{0x3107, 0x01},
4108a77009bSShunqian Zheng 	{0x3108, 0x05},
4118a77009bSShunqian Zheng 	{0x3500, 0x00},
4128a77009bSShunqian Zheng 	{0x3501, 0x3e},
4138a77009bSShunqian Zheng 	{0x3502, 0x00},
4148a77009bSShunqian Zheng 	{0x3503, 0x08},
4158a77009bSShunqian Zheng 	{0x3504, 0x03},
4168a77009bSShunqian Zheng 	{0x3505, 0x8c},
4178a77009bSShunqian Zheng 	{0x3507, 0x03},
4188a77009bSShunqian Zheng 	{0x3508, 0x00},
4198a77009bSShunqian Zheng 	{0x3509, 0x10},
4208a77009bSShunqian Zheng 	{0x350c, 0x00},
4218a77009bSShunqian Zheng 	{0x350d, 0x80},
4228a77009bSShunqian Zheng 	{0x3510, 0x00},
4238a77009bSShunqian Zheng 	{0x3511, 0x02},
4248a77009bSShunqian Zheng 	{0x3512, 0x00},
4258a77009bSShunqian Zheng 	{0x3601, 0x55},
4268a77009bSShunqian Zheng 	{0x3602, 0x58},
4278a77009bSShunqian Zheng 	{0x3611, 0x58},
4288a77009bSShunqian Zheng 	{0x3614, 0x30},
4298a77009bSShunqian Zheng 	{0x3615, 0x77},
4308a77009bSShunqian Zheng 	{0x3621, 0x08},
4318a77009bSShunqian Zheng 	{0x3624, 0x40},
4328a77009bSShunqian Zheng 	{0x3633, 0x0c},
4338a77009bSShunqian Zheng 	{0x3634, 0x0c},
4348a77009bSShunqian Zheng 	{0x3635, 0x0c},
4358a77009bSShunqian Zheng 	{0x3636, 0x0c},
4368a77009bSShunqian Zheng 	{0x3638, 0x00},
4378a77009bSShunqian Zheng 	{0x3639, 0x00},
4388a77009bSShunqian Zheng 	{0x363a, 0x00},
4398a77009bSShunqian Zheng 	{0x363b, 0x00},
4408a77009bSShunqian Zheng 	{0x363c, 0xff},
4418a77009bSShunqian Zheng 	{0x363d, 0xfa},
4428a77009bSShunqian Zheng 	{0x3650, 0x44},
4438a77009bSShunqian Zheng 	{0x3651, 0x44},
4448a77009bSShunqian Zheng 	{0x3652, 0x44},
4458a77009bSShunqian Zheng 	{0x3653, 0x44},
4468a77009bSShunqian Zheng 	{0x3654, 0x44},
4478a77009bSShunqian Zheng 	{0x3655, 0x44},
4488a77009bSShunqian Zheng 	{0x3656, 0x44},
4498a77009bSShunqian Zheng 	{0x3657, 0x44},
4508a77009bSShunqian Zheng 	{0x3660, 0x00},
4518a77009bSShunqian Zheng 	{0x3661, 0x00},
4528a77009bSShunqian Zheng 	{0x3662, 0x00},
4538a77009bSShunqian Zheng 	{0x366a, 0x00},
4548a77009bSShunqian Zheng 	{0x366e, 0x0c},
4558a77009bSShunqian Zheng 	{0x3673, 0x04},
4568a77009bSShunqian Zheng 	{0x3700, 0x14},
4578a77009bSShunqian Zheng 	{0x3703, 0x0c},
4588a77009bSShunqian Zheng 	{0x3706, 0x24},
4598a77009bSShunqian Zheng 	{0x3714, 0x27},
4608a77009bSShunqian Zheng 	{0x3715, 0x01},
4618a77009bSShunqian Zheng 	{0x3716, 0x00},
4628a77009bSShunqian Zheng 	{0x3717, 0x02},
4638a77009bSShunqian Zheng 	{0x3733, 0x10},
4648a77009bSShunqian Zheng 	{0x3734, 0x40},
4658a77009bSShunqian Zheng 	{0x373f, 0xa0},
4668a77009bSShunqian Zheng 	{0x3765, 0x20},
4678a77009bSShunqian Zheng 	{0x37a1, 0x1d},
4688a77009bSShunqian Zheng 	{0x37a8, 0x26},
4698a77009bSShunqian Zheng 	{0x37ab, 0x14},
4708a77009bSShunqian Zheng 	{0x37c2, 0x04},
4718a77009bSShunqian Zheng 	{0x37c3, 0xf0},
4728a77009bSShunqian Zheng 	{0x37cb, 0x09},
4738a77009bSShunqian Zheng 	{0x37cc, 0x13},
4748a77009bSShunqian Zheng 	{0x37cd, 0x1f},
4758a77009bSShunqian Zheng 	{0x37ce, 0x1f},
4768a77009bSShunqian Zheng 	{0x3800, 0x00},
4778a77009bSShunqian Zheng 	{0x3801, 0x00},
4788a77009bSShunqian Zheng 	{0x3802, 0x00},
4798a77009bSShunqian Zheng 	{0x3803, 0x00},
4808a77009bSShunqian Zheng 	{0x3804, 0x0a},
4818a77009bSShunqian Zheng 	{0x3805, 0x3f},
4828a77009bSShunqian Zheng 	{0x3806, 0x07},
4838a77009bSShunqian Zheng 	{0x3807, 0xaf},
4848a77009bSShunqian Zheng 	{0x3808, 0x05},
4858a77009bSShunqian Zheng 	{0x3809, 0x10},
4868a77009bSShunqian Zheng 	{0x380a, 0x03},
4878a77009bSShunqian Zheng 	{0x380b, 0xcc},
4888a77009bSShunqian Zheng 	{0x380c, 0x02},
4898a77009bSShunqian Zheng 	{0x380d, 0xe4},
4908a77009bSShunqian Zheng 	{0x380e, 0x03},
4918a77009bSShunqian Zheng 	{0x380f, 0xf4},
4928a77009bSShunqian Zheng 	{0x3810, 0x00},
4938a77009bSShunqian Zheng 	{0x3811, 0x00},
4948a77009bSShunqian Zheng 	{0x3812, 0x00},
4958a77009bSShunqian Zheng 	{0x3813, 0x06},
4968a77009bSShunqian Zheng 	{0x3814, 0x03},
4978a77009bSShunqian Zheng 	{0x3815, 0x01},
4988a77009bSShunqian Zheng 	{0x3816, 0x03},
4998a77009bSShunqian Zheng 	{0x3817, 0x01},
5008a77009bSShunqian Zheng 	{0x3818, 0x00},
5018a77009bSShunqian Zheng 	{0x3819, 0x00},
5028a77009bSShunqian Zheng 	{0x381a, 0x00},
5038a77009bSShunqian Zheng 	{0x381b, 0x01},
5048a77009bSShunqian Zheng 	{0x3820, 0x8b},
5058a77009bSShunqian Zheng 	{0x3821, 0x01},
5068a77009bSShunqian Zheng 	{0x3c80, 0x08},
5078a77009bSShunqian Zheng 	{0x3c82, 0x00},
5088a77009bSShunqian Zheng 	{0x3c83, 0x00},
5098a77009bSShunqian Zheng 	{0x3c88, 0x00},
5108a77009bSShunqian Zheng 	{0x3d85, 0x14},
5118a77009bSShunqian Zheng 	{0x3f02, 0x08},
5128a77009bSShunqian Zheng 	{0x3f03, 0x10},
5138a77009bSShunqian Zheng 	{0x4008, 0x02},
5148a77009bSShunqian Zheng 	{0x4009, 0x09},
5158a77009bSShunqian Zheng 	{0x404e, 0x20},
5168a77009bSShunqian Zheng 	{0x4501, 0x00},
5178a77009bSShunqian Zheng 	{0x4502, 0x10},
5188a77009bSShunqian Zheng 	{0x4800, 0x00},
5198a77009bSShunqian Zheng 	{0x481f, 0x2a},
5208a77009bSShunqian Zheng 	{0x4837, 0x13},
5218a77009bSShunqian Zheng 	{0x5000, 0x13},
5228a77009bSShunqian Zheng 	{0x5780, 0x3e},
5238a77009bSShunqian Zheng 	{0x5781, 0x0f},
5248a77009bSShunqian Zheng 	{0x5782, 0x44},
5258a77009bSShunqian Zheng 	{0x5783, 0x02},
5268a77009bSShunqian Zheng 	{0x5784, 0x01},
5278a77009bSShunqian Zheng 	{0x5785, 0x01},
5288a77009bSShunqian Zheng 	{0x5786, 0x00},
5298a77009bSShunqian Zheng 	{0x5787, 0x04},
5308a77009bSShunqian Zheng 	{0x5788, 0x02},
5318a77009bSShunqian Zheng 	{0x5789, 0x0f},
5328a77009bSShunqian Zheng 	{0x578a, 0xfd},
5338a77009bSShunqian Zheng 	{0x578b, 0xf5},
5348a77009bSShunqian Zheng 	{0x578c, 0xf5},
5358a77009bSShunqian Zheng 	{0x578d, 0x03},
5368a77009bSShunqian Zheng 	{0x578e, 0x08},
5378a77009bSShunqian Zheng 	{0x578f, 0x0c},
5388a77009bSShunqian Zheng 	{0x5790, 0x08},
5398a77009bSShunqian Zheng 	{0x5791, 0x06},
5408a77009bSShunqian Zheng 	{0x5792, 0x00},
5418a77009bSShunqian Zheng 	{0x5793, 0x52},
5428a77009bSShunqian Zheng 	{0x5794, 0xa3},
5438a77009bSShunqian Zheng 	{0x5b00, 0x00},
5448a77009bSShunqian Zheng 	{0x5b01, 0x1c},
5458a77009bSShunqian Zheng 	{0x5b02, 0x00},
5468a77009bSShunqian Zheng 	{0x5b03, 0x7f},
5478a77009bSShunqian Zheng 	{0x5b05, 0x6c},
5488a77009bSShunqian Zheng 	{0x5e10, 0xfc},
5498a77009bSShunqian Zheng 	{0x4010, 0xf1},
5508a77009bSShunqian Zheng 	{0x3503, 0x08},
5518a77009bSShunqian Zheng 	{0x3505, 0x8c},
5528a77009bSShunqian Zheng 	{0x3507, 0x03},
5538a77009bSShunqian Zheng 	{0x3508, 0x00},
5548a77009bSShunqian Zheng 	{0x3509, 0xf8},
5558a77009bSShunqian Zheng 	{0x0100, 0x01},
5568a77009bSShunqian Zheng 	{REG_NULL, 0x00}
5578a77009bSShunqian Zheng };
5588a77009bSShunqian Zheng 
5598a77009bSShunqian Zheng /*
5608a77009bSShunqian Zheng  * Xclk 24Mhz
5618a77009bSShunqian Zheng  * Pclk 45Mhz
5628a77009bSShunqian Zheng  * linelength 672(0x2a0)
5638a77009bSShunqian Zheng  * framelength 2232(0x8b8)
5648a77009bSShunqian Zheng  * grabwindow_width 1280
5658a77009bSShunqian Zheng  * grabwindow_height 720
5668a77009bSShunqian Zheng  * max_framerate 30fps
5678a77009bSShunqian Zheng  * mipi_datarate per lane 840Mbps
5688a77009bSShunqian Zheng  */
5698a77009bSShunqian Zheng static const struct regval ov5695_1280x720_regs[] = {
5708a77009bSShunqian Zheng 	{0x3501, 0x45},
5718a77009bSShunqian Zheng 	{0x366e, 0x0c},
5728a77009bSShunqian Zheng 	{0x3800, 0x00},
5738a77009bSShunqian Zheng 	{0x3801, 0x00},
5748a77009bSShunqian Zheng 	{0x3802, 0x01},
5758a77009bSShunqian Zheng 	{0x3803, 0x00},
5768a77009bSShunqian Zheng 	{0x3804, 0x0a},
5778a77009bSShunqian Zheng 	{0x3805, 0x3f},
5788a77009bSShunqian Zheng 	{0x3806, 0x06},
5798a77009bSShunqian Zheng 	{0x3807, 0xaf},
5808a77009bSShunqian Zheng 	{0x3808, 0x05},
5818a77009bSShunqian Zheng 	{0x3809, 0x00},
5828a77009bSShunqian Zheng 	{0x380a, 0x02},
5838a77009bSShunqian Zheng 	{0x380b, 0xd0},
5848a77009bSShunqian Zheng 	{0x380c, 0x02},
5858a77009bSShunqian Zheng 	{0x380d, 0xa0},
5868a77009bSShunqian Zheng 	{0x380e, 0x08},
5878a77009bSShunqian Zheng 	{0x380f, 0xb8},
5888a77009bSShunqian Zheng 	{0x3811, 0x06},
5898a77009bSShunqian Zheng 	{0x3813, 0x02},
5908a77009bSShunqian Zheng 	{0x3814, 0x03},
5918a77009bSShunqian Zheng 	{0x3816, 0x03},
5928a77009bSShunqian Zheng 	{0x3817, 0x01},
5938a77009bSShunqian Zheng 	{0x3820, 0x8b},
5948a77009bSShunqian Zheng 	{0x3821, 0x01},
5958a77009bSShunqian Zheng 	{0x4501, 0x00},
5968a77009bSShunqian Zheng 	{0x4008, 0x02},
5978a77009bSShunqian Zheng 	{0x4009, 0x09},
5988a77009bSShunqian Zheng 	{REG_NULL, 0x00}
5998a77009bSShunqian Zheng };
6008a77009bSShunqian Zheng 
6018a77009bSShunqian Zheng /*
6028a77009bSShunqian Zheng  * Xclk 24Mhz
6038a77009bSShunqian Zheng  * Pclk 45Mhz
6048a77009bSShunqian Zheng  * linelength 672(0x2a0)
6058a77009bSShunqian Zheng  * framelength 558(0x22e)
6068a77009bSShunqian Zheng  * grabwindow_width 640
6078a77009bSShunqian Zheng  * grabwindow_height 480
6088a77009bSShunqian Zheng  * max_framerate 120fps
6098a77009bSShunqian Zheng  * mipi_datarate per lane 840Mbps
6108a77009bSShunqian Zheng  */
6118a77009bSShunqian Zheng static const struct regval ov5695_640x480_regs[] = {
6128a77009bSShunqian Zheng 	{0x3501, 0x22},
6138a77009bSShunqian Zheng 	{0x366e, 0x0c},
6148a77009bSShunqian Zheng 	{0x3800, 0x00},
6158a77009bSShunqian Zheng 	{0x3801, 0x00},
6168a77009bSShunqian Zheng 	{0x3802, 0x00},
6178a77009bSShunqian Zheng 	{0x3803, 0x08},
6188a77009bSShunqian Zheng 	{0x3804, 0x0a},
6198a77009bSShunqian Zheng 	{0x3805, 0x3f},
6208a77009bSShunqian Zheng 	{0x3806, 0x07},
6218a77009bSShunqian Zheng 	{0x3807, 0xa7},
6228a77009bSShunqian Zheng 	{0x3808, 0x02},
6238a77009bSShunqian Zheng 	{0x3809, 0x80},
6248a77009bSShunqian Zheng 	{0x380a, 0x01},
6258a77009bSShunqian Zheng 	{0x380b, 0xe0},
6268a77009bSShunqian Zheng 	{0x380c, 0x02},
6278a77009bSShunqian Zheng 	{0x380d, 0xa0},
6288a77009bSShunqian Zheng 	{0x380e, 0x02},
6298a77009bSShunqian Zheng 	{0x380f, 0x2e},
6308a77009bSShunqian Zheng 	{0x3811, 0x06},
6318a77009bSShunqian Zheng 	{0x3813, 0x04},
6328a77009bSShunqian Zheng 	{0x3814, 0x07},
6338a77009bSShunqian Zheng 	{0x3816, 0x05},
6348a77009bSShunqian Zheng 	{0x3817, 0x03},
6358a77009bSShunqian Zheng 	{0x3820, 0x8d},
6368a77009bSShunqian Zheng 	{0x3821, 0x01},
6378a77009bSShunqian Zheng 	{0x4501, 0x00},
6388a77009bSShunqian Zheng 	{0x4008, 0x02},
6398a77009bSShunqian Zheng 	{0x4009, 0x09},
6408a77009bSShunqian Zheng 	{REG_NULL, 0x00}
6418a77009bSShunqian Zheng };
6428a77009bSShunqian Zheng 
6438a77009bSShunqian Zheng static const struct ov5695_mode supported_modes[] = {
6448a77009bSShunqian Zheng 	{
6458a77009bSShunqian Zheng 		.width = 2592,
6468a77009bSShunqian Zheng 		.height = 1944,
6478a77009bSShunqian Zheng 		.max_fps = 30,
6488a77009bSShunqian Zheng 		.exp_def = 0x0450,
6498a77009bSShunqian Zheng 		.hts_def = 0x02e4 * 4,
6508a77009bSShunqian Zheng 		.vts_def = 0x07e8,
6518a77009bSShunqian Zheng 		.reg_list = ov5695_2592x1944_regs,
6528a77009bSShunqian Zheng 	},
6538a77009bSShunqian Zheng 	{
6548a77009bSShunqian Zheng 		.width = 1920,
6558a77009bSShunqian Zheng 		.height = 1080,
6568a77009bSShunqian Zheng 		.max_fps = 30,
6578a77009bSShunqian Zheng 		.exp_def = 0x0450,
6588a77009bSShunqian Zheng 		.hts_def = 0x02a0 * 4,
6598a77009bSShunqian Zheng 		.vts_def = 0x08b8,
6608a77009bSShunqian Zheng 		.reg_list = ov5695_1920x1080_regs,
6618a77009bSShunqian Zheng 	},
6628a77009bSShunqian Zheng 	{
6638a77009bSShunqian Zheng 		.width = 1296,
6648a77009bSShunqian Zheng 		.height = 972,
6658a77009bSShunqian Zheng 		.max_fps = 60,
6668a77009bSShunqian Zheng 		.exp_def = 0x03e0,
6678a77009bSShunqian Zheng 		.hts_def = 0x02e4 * 4,
6688a77009bSShunqian Zheng 		.vts_def = 0x03f4,
6698a77009bSShunqian Zheng 		.reg_list = ov5695_1296x972_regs,
6708a77009bSShunqian Zheng 	},
6718a77009bSShunqian Zheng 	{
6728a77009bSShunqian Zheng 		.width = 1280,
6738a77009bSShunqian Zheng 		.height = 720,
6748a77009bSShunqian Zheng 		.max_fps = 30,
6758a77009bSShunqian Zheng 		.exp_def = 0x0450,
6768a77009bSShunqian Zheng 		.hts_def = 0x02a0 * 4,
6778a77009bSShunqian Zheng 		.vts_def = 0x08b8,
6788a77009bSShunqian Zheng 		.reg_list = ov5695_1280x720_regs,
6798a77009bSShunqian Zheng 	},
6808a77009bSShunqian Zheng 	{
6818a77009bSShunqian Zheng 		.width = 640,
6828a77009bSShunqian Zheng 		.height = 480,
6838a77009bSShunqian Zheng 		.max_fps = 120,
6848a77009bSShunqian Zheng 		.exp_def = 0x0450,
6858a77009bSShunqian Zheng 		.hts_def = 0x02a0 * 4,
6868a77009bSShunqian Zheng 		.vts_def = 0x022e,
6878a77009bSShunqian Zheng 		.reg_list = ov5695_640x480_regs,
6888a77009bSShunqian Zheng 	},
6898a77009bSShunqian Zheng };
6908a77009bSShunqian Zheng 
6918a77009bSShunqian Zheng #define OV5695_LINK_FREQ_420MHZ		420000000
6928a77009bSShunqian Zheng static const s64 link_freq_menu_items[] = {
6938a77009bSShunqian Zheng 	OV5695_LINK_FREQ_420MHZ
6948a77009bSShunqian Zheng };
6958a77009bSShunqian Zheng 
6968a77009bSShunqian Zheng static const char * const ov5695_test_pattern_menu[] = {
6978a77009bSShunqian Zheng 	"Disabled",
6988a77009bSShunqian Zheng 	"Vertical Color Bar Type 1",
6998a77009bSShunqian Zheng 	"Vertical Color Bar Type 2",
7008a77009bSShunqian Zheng 	"Vertical Color Bar Type 3",
7018a77009bSShunqian Zheng 	"Vertical Color Bar Type 4"
7028a77009bSShunqian Zheng };
7038a77009bSShunqian Zheng 
7048a77009bSShunqian Zheng /* Write registers up to 4 at a time */
ov5695_write_reg(struct i2c_client * client,u16 reg,u32 len,u32 val)7058a77009bSShunqian Zheng static int ov5695_write_reg(struct i2c_client *client, u16 reg,
7068a77009bSShunqian Zheng 			    u32 len, u32 val)
7078a77009bSShunqian Zheng {
7088a77009bSShunqian Zheng 	u32 buf_i, val_i;
7098a77009bSShunqian Zheng 	u8 buf[6];
7108a77009bSShunqian Zheng 	u8 *val_p;
7118a77009bSShunqian Zheng 	__be32 val_be;
7128a77009bSShunqian Zheng 
7138a77009bSShunqian Zheng 	if (len > 4)
7148a77009bSShunqian Zheng 		return -EINVAL;
7158a77009bSShunqian Zheng 
7168a77009bSShunqian Zheng 	buf[0] = reg >> 8;
7178a77009bSShunqian Zheng 	buf[1] = reg & 0xff;
7188a77009bSShunqian Zheng 
7198a77009bSShunqian Zheng 	val_be = cpu_to_be32(val);
7208a77009bSShunqian Zheng 	val_p = (u8 *)&val_be;
7218a77009bSShunqian Zheng 	buf_i = 2;
7228a77009bSShunqian Zheng 	val_i = 4 - len;
7238a77009bSShunqian Zheng 
7248a77009bSShunqian Zheng 	while (val_i < 4)
7258a77009bSShunqian Zheng 		buf[buf_i++] = val_p[val_i++];
7268a77009bSShunqian Zheng 
7278a77009bSShunqian Zheng 	if (i2c_master_send(client, buf, len + 2) != len + 2)
7288a77009bSShunqian Zheng 		return -EIO;
7298a77009bSShunqian Zheng 
7308a77009bSShunqian Zheng 	return 0;
7318a77009bSShunqian Zheng }
7328a77009bSShunqian Zheng 
ov5695_write_array(struct i2c_client * client,const struct regval * regs)7338a77009bSShunqian Zheng static int ov5695_write_array(struct i2c_client *client,
7348a77009bSShunqian Zheng 			      const struct regval *regs)
7358a77009bSShunqian Zheng {
7368a77009bSShunqian Zheng 	u32 i;
7378a77009bSShunqian Zheng 	int ret = 0;
7388a77009bSShunqian Zheng 
7398a77009bSShunqian Zheng 	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
7408a77009bSShunqian Zheng 		ret = ov5695_write_reg(client, regs[i].addr,
7418a77009bSShunqian Zheng 				       OV5695_REG_VALUE_08BIT, regs[i].val);
7428a77009bSShunqian Zheng 
7438a77009bSShunqian Zheng 	return ret;
7448a77009bSShunqian Zheng }
7458a77009bSShunqian Zheng 
7468a77009bSShunqian Zheng /* Read registers up to 4 at a time */
ov5695_read_reg(struct i2c_client * client,u16 reg,unsigned int len,u32 * val)7478a77009bSShunqian Zheng static int ov5695_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
7488a77009bSShunqian Zheng 			   u32 *val)
7498a77009bSShunqian Zheng {
7508a77009bSShunqian Zheng 	struct i2c_msg msgs[2];
7518a77009bSShunqian Zheng 	u8 *data_be_p;
7528a77009bSShunqian Zheng 	__be32 data_be = 0;
7538a77009bSShunqian Zheng 	__be16 reg_addr_be = cpu_to_be16(reg);
7548a77009bSShunqian Zheng 	int ret;
7558a77009bSShunqian Zheng 
7568a77009bSShunqian Zheng 	if (len > 4)
7578a77009bSShunqian Zheng 		return -EINVAL;
7588a77009bSShunqian Zheng 
7598a77009bSShunqian Zheng 	data_be_p = (u8 *)&data_be;
7608a77009bSShunqian Zheng 	/* Write register address */
7618a77009bSShunqian Zheng 	msgs[0].addr = client->addr;
7628a77009bSShunqian Zheng 	msgs[0].flags = 0;
7638a77009bSShunqian Zheng 	msgs[0].len = 2;
7648a77009bSShunqian Zheng 	msgs[0].buf = (u8 *)&reg_addr_be;
7658a77009bSShunqian Zheng 
7668a77009bSShunqian Zheng 	/* Read data from register */
7678a77009bSShunqian Zheng 	msgs[1].addr = client->addr;
7688a77009bSShunqian Zheng 	msgs[1].flags = I2C_M_RD;
7698a77009bSShunqian Zheng 	msgs[1].len = len;
7708a77009bSShunqian Zheng 	msgs[1].buf = &data_be_p[4 - len];
7718a77009bSShunqian Zheng 
7728a77009bSShunqian Zheng 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
7738a77009bSShunqian Zheng 	if (ret != ARRAY_SIZE(msgs))
7748a77009bSShunqian Zheng 		return -EIO;
7758a77009bSShunqian Zheng 
7768a77009bSShunqian Zheng 	*val = be32_to_cpu(data_be);
7778a77009bSShunqian Zheng 
7788a77009bSShunqian Zheng 	return 0;
7798a77009bSShunqian Zheng }
7808a77009bSShunqian Zheng 
ov5695_get_reso_dist(const struct ov5695_mode * mode,struct v4l2_mbus_framefmt * framefmt)7818a77009bSShunqian Zheng static int ov5695_get_reso_dist(const struct ov5695_mode *mode,
7828a77009bSShunqian Zheng 				struct v4l2_mbus_framefmt *framefmt)
7838a77009bSShunqian Zheng {
7848a77009bSShunqian Zheng 	return abs(mode->width - framefmt->width) +
7858a77009bSShunqian Zheng 	       abs(mode->height - framefmt->height);
7868a77009bSShunqian Zheng }
7878a77009bSShunqian Zheng 
7888a77009bSShunqian Zheng static const struct ov5695_mode *
ov5695_find_best_fit(struct v4l2_subdev_format * fmt)7898a77009bSShunqian Zheng ov5695_find_best_fit(struct v4l2_subdev_format *fmt)
7908a77009bSShunqian Zheng {
7918a77009bSShunqian Zheng 	struct v4l2_mbus_framefmt *framefmt = &fmt->format;
7928a77009bSShunqian Zheng 	int dist;
7938a77009bSShunqian Zheng 	int cur_best_fit = 0;
7948a77009bSShunqian Zheng 	int cur_best_fit_dist = -1;
7958a77009bSShunqian Zheng 	int i;
7968a77009bSShunqian Zheng 
7978a77009bSShunqian Zheng 	for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
7988a77009bSShunqian Zheng 		dist = ov5695_get_reso_dist(&supported_modes[i], framefmt);
7998a77009bSShunqian Zheng 		if (cur_best_fit_dist == -1 || dist < cur_best_fit_dist) {
8008a77009bSShunqian Zheng 			cur_best_fit_dist = dist;
8018a77009bSShunqian Zheng 			cur_best_fit = i;
8028a77009bSShunqian Zheng 		}
8038a77009bSShunqian Zheng 	}
8048a77009bSShunqian Zheng 
8058a77009bSShunqian Zheng 	return &supported_modes[cur_best_fit];
8068a77009bSShunqian Zheng }
8078a77009bSShunqian Zheng 
ov5695_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)8088a77009bSShunqian Zheng static int ov5695_set_fmt(struct v4l2_subdev *sd,
8090d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
8108a77009bSShunqian Zheng 			  struct v4l2_subdev_format *fmt)
8118a77009bSShunqian Zheng {
8128a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
8138a77009bSShunqian Zheng 	const struct ov5695_mode *mode;
8148a77009bSShunqian Zheng 	s64 h_blank, vblank_def;
8158a77009bSShunqian Zheng 
8168a77009bSShunqian Zheng 	mutex_lock(&ov5695->mutex);
8178a77009bSShunqian Zheng 
8188a77009bSShunqian Zheng 	mode = ov5695_find_best_fit(fmt);
8198a77009bSShunqian Zheng 	fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
8208a77009bSShunqian Zheng 	fmt->format.width = mode->width;
8218a77009bSShunqian Zheng 	fmt->format.height = mode->height;
8228a77009bSShunqian Zheng 	fmt->format.field = V4L2_FIELD_NONE;
8238a77009bSShunqian Zheng 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
8248a77009bSShunqian Zheng #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
8250d346d2aSTomi Valkeinen 		*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) = fmt->format;
8268a77009bSShunqian Zheng #endif
8278a77009bSShunqian Zheng 	} else {
8288a77009bSShunqian Zheng 		ov5695->cur_mode = mode;
8298a77009bSShunqian Zheng 		h_blank = mode->hts_def - mode->width;
8308a77009bSShunqian Zheng 		__v4l2_ctrl_modify_range(ov5695->hblank, h_blank,
8318a77009bSShunqian Zheng 					 h_blank, 1, h_blank);
8328a77009bSShunqian Zheng 		vblank_def = mode->vts_def - mode->height;
8338a77009bSShunqian Zheng 		__v4l2_ctrl_modify_range(ov5695->vblank, vblank_def,
8348a77009bSShunqian Zheng 					 OV5695_VTS_MAX - mode->height,
8358a77009bSShunqian Zheng 					 1, vblank_def);
8368a77009bSShunqian Zheng 	}
8378a77009bSShunqian Zheng 
8388a77009bSShunqian Zheng 	mutex_unlock(&ov5695->mutex);
8398a77009bSShunqian Zheng 
8408a77009bSShunqian Zheng 	return 0;
8418a77009bSShunqian Zheng }
8428a77009bSShunqian Zheng 
ov5695_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)8438a77009bSShunqian Zheng static int ov5695_get_fmt(struct v4l2_subdev *sd,
8440d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
8458a77009bSShunqian Zheng 			  struct v4l2_subdev_format *fmt)
8468a77009bSShunqian Zheng {
8478a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
8488a77009bSShunqian Zheng 	const struct ov5695_mode *mode = ov5695->cur_mode;
8498a77009bSShunqian Zheng 
8508a77009bSShunqian Zheng 	mutex_lock(&ov5695->mutex);
8518a77009bSShunqian Zheng 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
8528a77009bSShunqian Zheng #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
8530d346d2aSTomi Valkeinen 		fmt->format = *v4l2_subdev_get_try_format(sd, sd_state,
8540d346d2aSTomi Valkeinen 							  fmt->pad);
8558a77009bSShunqian Zheng #else
8568a77009bSShunqian Zheng 		mutex_unlock(&ov5695->mutex);
8572dbcb6fbSHans Verkuil 		return -EINVAL;
8588a77009bSShunqian Zheng #endif
8598a77009bSShunqian Zheng 	} else {
8608a77009bSShunqian Zheng 		fmt->format.width = mode->width;
8618a77009bSShunqian Zheng 		fmt->format.height = mode->height;
8628a77009bSShunqian Zheng 		fmt->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
8638a77009bSShunqian Zheng 		fmt->format.field = V4L2_FIELD_NONE;
8648a77009bSShunqian Zheng 	}
8658a77009bSShunqian Zheng 	mutex_unlock(&ov5695->mutex);
8668a77009bSShunqian Zheng 
8678a77009bSShunqian Zheng 	return 0;
8688a77009bSShunqian Zheng }
8698a77009bSShunqian Zheng 
ov5695_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)8708a77009bSShunqian Zheng static int ov5695_enum_mbus_code(struct v4l2_subdev *sd,
8710d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
8728a77009bSShunqian Zheng 				 struct v4l2_subdev_mbus_code_enum *code)
8738a77009bSShunqian Zheng {
8748a77009bSShunqian Zheng 	if (code->index != 0)
8758a77009bSShunqian Zheng 		return -EINVAL;
8768a77009bSShunqian Zheng 	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
8778a77009bSShunqian Zheng 
8788a77009bSShunqian Zheng 	return 0;
8798a77009bSShunqian Zheng }
8808a77009bSShunqian Zheng 
ov5695_enum_frame_sizes(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)8818a77009bSShunqian Zheng static int ov5695_enum_frame_sizes(struct v4l2_subdev *sd,
8820d346d2aSTomi Valkeinen 				   struct v4l2_subdev_state *sd_state,
8838a77009bSShunqian Zheng 				   struct v4l2_subdev_frame_size_enum *fse)
8848a77009bSShunqian Zheng {
885f68e68d2SDan Carpenter 	if (fse->index >= ARRAY_SIZE(supported_modes))
8868a77009bSShunqian Zheng 		return -EINVAL;
8878a77009bSShunqian Zheng 
8888a77009bSShunqian Zheng 	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
8898a77009bSShunqian Zheng 		return -EINVAL;
8908a77009bSShunqian Zheng 
8918a77009bSShunqian Zheng 	fse->min_width  = supported_modes[fse->index].width;
8928a77009bSShunqian Zheng 	fse->max_width  = supported_modes[fse->index].width;
8938a77009bSShunqian Zheng 	fse->max_height = supported_modes[fse->index].height;
8948a77009bSShunqian Zheng 	fse->min_height = supported_modes[fse->index].height;
8958a77009bSShunqian Zheng 
8968a77009bSShunqian Zheng 	return 0;
8978a77009bSShunqian Zheng }
8988a77009bSShunqian Zheng 
ov5695_enable_test_pattern(struct ov5695 * ov5695,u32 pattern)8998a77009bSShunqian Zheng static int ov5695_enable_test_pattern(struct ov5695 *ov5695, u32 pattern)
9008a77009bSShunqian Zheng {
9018a77009bSShunqian Zheng 	u32 val;
9028a77009bSShunqian Zheng 
9038a77009bSShunqian Zheng 	if (pattern)
9048a77009bSShunqian Zheng 		val = (pattern - 1) | OV5695_TEST_PATTERN_ENABLE;
9058a77009bSShunqian Zheng 	else
9068a77009bSShunqian Zheng 		val = OV5695_TEST_PATTERN_DISABLE;
9078a77009bSShunqian Zheng 
9088a77009bSShunqian Zheng 	return ov5695_write_reg(ov5695->client, OV5695_REG_TEST_PATTERN,
9098a77009bSShunqian Zheng 				OV5695_REG_VALUE_08BIT, val);
9108a77009bSShunqian Zheng }
9118a77009bSShunqian Zheng 
__ov5695_start_stream(struct ov5695 * ov5695)9128a77009bSShunqian Zheng static int __ov5695_start_stream(struct ov5695 *ov5695)
9138a77009bSShunqian Zheng {
9148a77009bSShunqian Zheng 	int ret;
9158a77009bSShunqian Zheng 
9168a77009bSShunqian Zheng 	ret = ov5695_write_array(ov5695->client, ov5695_global_regs);
9178a77009bSShunqian Zheng 	if (ret)
9188a77009bSShunqian Zheng 		return ret;
9198a77009bSShunqian Zheng 	ret = ov5695_write_array(ov5695->client, ov5695->cur_mode->reg_list);
9208a77009bSShunqian Zheng 	if (ret)
9218a77009bSShunqian Zheng 		return ret;
9228a77009bSShunqian Zheng 
9238a77009bSShunqian Zheng 	/* In case these controls are set before streaming */
9248a77009bSShunqian Zheng 	ret = __v4l2_ctrl_handler_setup(&ov5695->ctrl_handler);
9258a77009bSShunqian Zheng 	if (ret)
9268a77009bSShunqian Zheng 		return ret;
9278a77009bSShunqian Zheng 
9288a77009bSShunqian Zheng 	return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE,
9298a77009bSShunqian Zheng 				OV5695_REG_VALUE_08BIT, OV5695_MODE_STREAMING);
9308a77009bSShunqian Zheng }
9318a77009bSShunqian Zheng 
__ov5695_stop_stream(struct ov5695 * ov5695)9328a77009bSShunqian Zheng static int __ov5695_stop_stream(struct ov5695 *ov5695)
9338a77009bSShunqian Zheng {
9348a77009bSShunqian Zheng 	return ov5695_write_reg(ov5695->client, OV5695_REG_CTRL_MODE,
9358a77009bSShunqian Zheng 				OV5695_REG_VALUE_08BIT, OV5695_MODE_SW_STANDBY);
9368a77009bSShunqian Zheng }
9378a77009bSShunqian Zheng 
ov5695_s_stream(struct v4l2_subdev * sd,int on)9388a77009bSShunqian Zheng static int ov5695_s_stream(struct v4l2_subdev *sd, int on)
9398a77009bSShunqian Zheng {
9408a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
9418a77009bSShunqian Zheng 	struct i2c_client *client = ov5695->client;
9428a77009bSShunqian Zheng 	int ret = 0;
9438a77009bSShunqian Zheng 
9448a77009bSShunqian Zheng 	mutex_lock(&ov5695->mutex);
9458a77009bSShunqian Zheng 	on = !!on;
9468a77009bSShunqian Zheng 	if (on == ov5695->streaming)
9478a77009bSShunqian Zheng 		goto unlock_and_return;
9488a77009bSShunqian Zheng 
9498a77009bSShunqian Zheng 	if (on) {
9501541ac5fSMauro Carvalho Chehab 		ret = pm_runtime_resume_and_get(&client->dev);
9511541ac5fSMauro Carvalho Chehab 		if (ret < 0)
9528a77009bSShunqian Zheng 			goto unlock_and_return;
9538a77009bSShunqian Zheng 
9548a77009bSShunqian Zheng 		ret = __ov5695_start_stream(ov5695);
9558a77009bSShunqian Zheng 		if (ret) {
9568a77009bSShunqian Zheng 			v4l2_err(sd, "start stream failed while write regs\n");
9578a77009bSShunqian Zheng 			pm_runtime_put(&client->dev);
9588a77009bSShunqian Zheng 			goto unlock_and_return;
9598a77009bSShunqian Zheng 		}
9608a77009bSShunqian Zheng 	} else {
9618a77009bSShunqian Zheng 		__ov5695_stop_stream(ov5695);
9628a77009bSShunqian Zheng 		pm_runtime_put(&client->dev);
9638a77009bSShunqian Zheng 	}
9648a77009bSShunqian Zheng 
9658a77009bSShunqian Zheng 	ov5695->streaming = on;
9668a77009bSShunqian Zheng 
9678a77009bSShunqian Zheng unlock_and_return:
9688a77009bSShunqian Zheng 	mutex_unlock(&ov5695->mutex);
9698a77009bSShunqian Zheng 
9708a77009bSShunqian Zheng 	return ret;
9718a77009bSShunqian Zheng }
9728a77009bSShunqian Zheng 
__ov5695_power_on(struct ov5695 * ov5695)9738a77009bSShunqian Zheng static int __ov5695_power_on(struct ov5695 *ov5695)
9748a77009bSShunqian Zheng {
975f1a64f56SDongchun Zhu 	int i, ret;
9768a77009bSShunqian Zheng 	struct device *dev = &ov5695->client->dev;
9778a77009bSShunqian Zheng 
9788a77009bSShunqian Zheng 	ret = clk_prepare_enable(ov5695->xvclk);
9798a77009bSShunqian Zheng 	if (ret < 0) {
9808a77009bSShunqian Zheng 		dev_err(dev, "Failed to enable xvclk\n");
9818a77009bSShunqian Zheng 		return ret;
9828a77009bSShunqian Zheng 	}
9838a77009bSShunqian Zheng 
9848a77009bSShunqian Zheng 	gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
9858a77009bSShunqian Zheng 
986f1a64f56SDongchun Zhu 	/*
987f1a64f56SDongchun Zhu 	 * The hardware requires the regulators to be powered on in order,
988f1a64f56SDongchun Zhu 	 * so enable them one by one.
989f1a64f56SDongchun Zhu 	 */
990f1a64f56SDongchun Zhu 	for (i = 0; i < OV5695_NUM_SUPPLIES; i++) {
991f1a64f56SDongchun Zhu 		ret = regulator_enable(ov5695->supplies[i].consumer);
992f1a64f56SDongchun Zhu 		if (ret) {
993f1a64f56SDongchun Zhu 			dev_err(dev, "Failed to enable %s: %d\n",
994f1a64f56SDongchun Zhu 				ov5695->supplies[i].supply, ret);
995f1a64f56SDongchun Zhu 			goto disable_reg_clk;
996f1a64f56SDongchun Zhu 		}
9978a77009bSShunqian Zheng 	}
9988a77009bSShunqian Zheng 
9998a77009bSShunqian Zheng 	gpiod_set_value_cansleep(ov5695->reset_gpio, 0);
10008a77009bSShunqian Zheng 
1001f1a64f56SDongchun Zhu 	usleep_range(1000, 1200);
10028a77009bSShunqian Zheng 
10038a77009bSShunqian Zheng 	return 0;
10048a77009bSShunqian Zheng 
1005f1a64f56SDongchun Zhu disable_reg_clk:
1006f1a64f56SDongchun Zhu 	for (--i; i >= 0; i--)
1007f1a64f56SDongchun Zhu 		regulator_disable(ov5695->supplies[i].consumer);
10088a77009bSShunqian Zheng 	clk_disable_unprepare(ov5695->xvclk);
10098a77009bSShunqian Zheng 
10108a77009bSShunqian Zheng 	return ret;
10118a77009bSShunqian Zheng }
10128a77009bSShunqian Zheng 
__ov5695_power_off(struct ov5695 * ov5695)10138a77009bSShunqian Zheng static void __ov5695_power_off(struct ov5695 *ov5695)
10148a77009bSShunqian Zheng {
1015f1a64f56SDongchun Zhu 	struct device *dev = &ov5695->client->dev;
1016f1a64f56SDongchun Zhu 	int i, ret;
1017f1a64f56SDongchun Zhu 
10188a77009bSShunqian Zheng 	clk_disable_unprepare(ov5695->xvclk);
10198a77009bSShunqian Zheng 	gpiod_set_value_cansleep(ov5695->reset_gpio, 1);
1020f1a64f56SDongchun Zhu 
1021f1a64f56SDongchun Zhu 	/*
1022f1a64f56SDongchun Zhu 	 * The hardware requires the regulators to be powered off in order,
1023f1a64f56SDongchun Zhu 	 * so disable them one by one.
1024f1a64f56SDongchun Zhu 	 */
1025f1a64f56SDongchun Zhu 	for (i = OV5695_NUM_SUPPLIES - 1; i >= 0; i--) {
1026f1a64f56SDongchun Zhu 		ret = regulator_disable(ov5695->supplies[i].consumer);
1027f1a64f56SDongchun Zhu 		if (ret)
1028f1a64f56SDongchun Zhu 			dev_err(dev, "Failed to disable %s: %d\n",
1029f1a64f56SDongchun Zhu 				ov5695->supplies[i].supply, ret);
1030f1a64f56SDongchun Zhu 	}
10318a77009bSShunqian Zheng }
10328a77009bSShunqian Zheng 
ov5695_runtime_resume(struct device * dev)103394d4a1a6SArnd Bergmann static int __maybe_unused ov5695_runtime_resume(struct device *dev)
10348a77009bSShunqian Zheng {
10358666b319SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
10368a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
10378a77009bSShunqian Zheng 
10388a77009bSShunqian Zheng 	return __ov5695_power_on(ov5695);
10398a77009bSShunqian Zheng }
10408a77009bSShunqian Zheng 
ov5695_runtime_suspend(struct device * dev)104194d4a1a6SArnd Bergmann static int __maybe_unused ov5695_runtime_suspend(struct device *dev)
10428a77009bSShunqian Zheng {
10438666b319SKrzysztof Kozlowski 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
10448a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
10458a77009bSShunqian Zheng 
10468a77009bSShunqian Zheng 	__ov5695_power_off(ov5695);
10478a77009bSShunqian Zheng 
10488a77009bSShunqian Zheng 	return 0;
10498a77009bSShunqian Zheng }
10508a77009bSShunqian Zheng 
10518a77009bSShunqian Zheng #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
ov5695_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)10528a77009bSShunqian Zheng static int ov5695_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
10538a77009bSShunqian Zheng {
10548a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
10558a77009bSShunqian Zheng 	struct v4l2_mbus_framefmt *try_fmt =
10560d346d2aSTomi Valkeinen 				v4l2_subdev_get_try_format(sd, fh->state, 0);
10578a77009bSShunqian Zheng 	const struct ov5695_mode *def_mode = &supported_modes[0];
10588a77009bSShunqian Zheng 
10598a77009bSShunqian Zheng 	mutex_lock(&ov5695->mutex);
10608a77009bSShunqian Zheng 	/* Initialize try_fmt */
10618a77009bSShunqian Zheng 	try_fmt->width = def_mode->width;
10628a77009bSShunqian Zheng 	try_fmt->height = def_mode->height;
10638a77009bSShunqian Zheng 	try_fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
10648a77009bSShunqian Zheng 	try_fmt->field = V4L2_FIELD_NONE;
10658a77009bSShunqian Zheng 
10668a77009bSShunqian Zheng 	mutex_unlock(&ov5695->mutex);
10678a77009bSShunqian Zheng 	/* No crop or compose */
10688a77009bSShunqian Zheng 
10698a77009bSShunqian Zheng 	return 0;
10708a77009bSShunqian Zheng }
10718a77009bSShunqian Zheng #endif
10728a77009bSShunqian Zheng 
10738a77009bSShunqian Zheng static const struct dev_pm_ops ov5695_pm_ops = {
10748a77009bSShunqian Zheng 	SET_RUNTIME_PM_OPS(ov5695_runtime_suspend,
10758a77009bSShunqian Zheng 			   ov5695_runtime_resume, NULL)
10768a77009bSShunqian Zheng };
10778a77009bSShunqian Zheng 
10788a77009bSShunqian Zheng #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
10798a77009bSShunqian Zheng static const struct v4l2_subdev_internal_ops ov5695_internal_ops = {
10808a77009bSShunqian Zheng 	.open = ov5695_open,
10818a77009bSShunqian Zheng };
10828a77009bSShunqian Zheng #endif
10838a77009bSShunqian Zheng 
10848a77009bSShunqian Zheng static const struct v4l2_subdev_video_ops ov5695_video_ops = {
10858a77009bSShunqian Zheng 	.s_stream = ov5695_s_stream,
10868a77009bSShunqian Zheng };
10878a77009bSShunqian Zheng 
10888a77009bSShunqian Zheng static const struct v4l2_subdev_pad_ops ov5695_pad_ops = {
10898a77009bSShunqian Zheng 	.enum_mbus_code = ov5695_enum_mbus_code,
10908a77009bSShunqian Zheng 	.enum_frame_size = ov5695_enum_frame_sizes,
10918a77009bSShunqian Zheng 	.get_fmt = ov5695_get_fmt,
10928a77009bSShunqian Zheng 	.set_fmt = ov5695_set_fmt,
10938a77009bSShunqian Zheng };
10948a77009bSShunqian Zheng 
10958a77009bSShunqian Zheng static const struct v4l2_subdev_ops ov5695_subdev_ops = {
10968a77009bSShunqian Zheng 	.video	= &ov5695_video_ops,
10978a77009bSShunqian Zheng 	.pad	= &ov5695_pad_ops,
10988a77009bSShunqian Zheng };
10998a77009bSShunqian Zheng 
ov5695_set_ctrl(struct v4l2_ctrl * ctrl)11008a77009bSShunqian Zheng static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
11018a77009bSShunqian Zheng {
11028a77009bSShunqian Zheng 	struct ov5695 *ov5695 = container_of(ctrl->handler,
11038a77009bSShunqian Zheng 					     struct ov5695, ctrl_handler);
11048a77009bSShunqian Zheng 	struct i2c_client *client = ov5695->client;
11058a77009bSShunqian Zheng 	s64 max;
11068a77009bSShunqian Zheng 	int ret = 0;
11078a77009bSShunqian Zheng 
11088a77009bSShunqian Zheng 	/* Propagate change of current control to all related controls */
11098a77009bSShunqian Zheng 	switch (ctrl->id) {
11108a77009bSShunqian Zheng 	case V4L2_CID_VBLANK:
11118a77009bSShunqian Zheng 		/* Update max exposure while meeting expected vblanking */
11128a77009bSShunqian Zheng 		max = ov5695->cur_mode->height + ctrl->val - 4;
11138a77009bSShunqian Zheng 		__v4l2_ctrl_modify_range(ov5695->exposure,
11148a77009bSShunqian Zheng 					 ov5695->exposure->minimum, max,
11158a77009bSShunqian Zheng 					 ov5695->exposure->step,
11168a77009bSShunqian Zheng 					 ov5695->exposure->default_value);
11178a77009bSShunqian Zheng 		break;
11188a77009bSShunqian Zheng 	}
11198a77009bSShunqian Zheng 
11204d471563SSakari Ailus 	if (!pm_runtime_get_if_in_use(&client->dev))
11218a77009bSShunqian Zheng 		return 0;
11228a77009bSShunqian Zheng 
11238a77009bSShunqian Zheng 	switch (ctrl->id) {
11248a77009bSShunqian Zheng 	case V4L2_CID_EXPOSURE:
1125ab0589afSJulia Lawall 		/* 4 least significant bits of exposure are fractional part */
11268a77009bSShunqian Zheng 		ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE,
11278a77009bSShunqian Zheng 				       OV5695_REG_VALUE_24BIT, ctrl->val << 4);
11288a77009bSShunqian Zheng 		break;
11298a77009bSShunqian Zheng 	case V4L2_CID_ANALOGUE_GAIN:
11308a77009bSShunqian Zheng 		ret = ov5695_write_reg(ov5695->client, OV5695_REG_ANALOG_GAIN,
11318a77009bSShunqian Zheng 				       OV5695_REG_VALUE_08BIT, ctrl->val);
11328a77009bSShunqian Zheng 		break;
11338a77009bSShunqian Zheng 	case V4L2_CID_DIGITAL_GAIN:
11348a77009bSShunqian Zheng 		ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_L,
11358a77009bSShunqian Zheng 				       OV5695_REG_VALUE_08BIT,
11368a77009bSShunqian Zheng 				       ctrl->val & OV5695_DIGI_GAIN_L_MASK);
11378a77009bSShunqian Zheng 		ret = ov5695_write_reg(ov5695->client, OV5695_REG_DIGI_GAIN_H,
11388a77009bSShunqian Zheng 				       OV5695_REG_VALUE_08BIT,
11398a77009bSShunqian Zheng 				       ctrl->val >> OV5695_DIGI_GAIN_H_SHIFT);
11408a77009bSShunqian Zheng 		break;
11418a77009bSShunqian Zheng 	case V4L2_CID_VBLANK:
11428a77009bSShunqian Zheng 		ret = ov5695_write_reg(ov5695->client, OV5695_REG_VTS,
11438a77009bSShunqian Zheng 				       OV5695_REG_VALUE_16BIT,
11448a77009bSShunqian Zheng 				       ctrl->val + ov5695->cur_mode->height);
11458a77009bSShunqian Zheng 		break;
11468a77009bSShunqian Zheng 	case V4L2_CID_TEST_PATTERN:
11478a77009bSShunqian Zheng 		ret = ov5695_enable_test_pattern(ov5695, ctrl->val);
11488a77009bSShunqian Zheng 		break;
11498a77009bSShunqian Zheng 	default:
11508a77009bSShunqian Zheng 		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
11518a77009bSShunqian Zheng 			 __func__, ctrl->id, ctrl->val);
11528a77009bSShunqian Zheng 		break;
115326092e7eSShobhit Kukreti 	}
11548a77009bSShunqian Zheng 
11558a77009bSShunqian Zheng 	pm_runtime_put(&client->dev);
11568a77009bSShunqian Zheng 
11578a77009bSShunqian Zheng 	return ret;
11588a77009bSShunqian Zheng }
11598a77009bSShunqian Zheng 
11608a77009bSShunqian Zheng static const struct v4l2_ctrl_ops ov5695_ctrl_ops = {
11618a77009bSShunqian Zheng 	.s_ctrl = ov5695_set_ctrl,
11628a77009bSShunqian Zheng };
11638a77009bSShunqian Zheng 
ov5695_initialize_controls(struct ov5695 * ov5695)11648a77009bSShunqian Zheng static int ov5695_initialize_controls(struct ov5695 *ov5695)
11658a77009bSShunqian Zheng {
11668a77009bSShunqian Zheng 	const struct ov5695_mode *mode;
11678a77009bSShunqian Zheng 	struct v4l2_ctrl_handler *handler;
11688a77009bSShunqian Zheng 	struct v4l2_ctrl *ctrl;
11698a77009bSShunqian Zheng 	s64 exposure_max, vblank_def;
11708a77009bSShunqian Zheng 	u32 h_blank;
11718a77009bSShunqian Zheng 	int ret;
11728a77009bSShunqian Zheng 
11738a77009bSShunqian Zheng 	handler = &ov5695->ctrl_handler;
11748a77009bSShunqian Zheng 	mode = ov5695->cur_mode;
11758a77009bSShunqian Zheng 	ret = v4l2_ctrl_handler_init(handler, 8);
11768a77009bSShunqian Zheng 	if (ret)
11778a77009bSShunqian Zheng 		return ret;
11788a77009bSShunqian Zheng 	handler->lock = &ov5695->mutex;
11798a77009bSShunqian Zheng 
11808a77009bSShunqian Zheng 	ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
11818a77009bSShunqian Zheng 				      0, 0, link_freq_menu_items);
11828a77009bSShunqian Zheng 	if (ctrl)
11838a77009bSShunqian Zheng 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
11848a77009bSShunqian Zheng 
11858a77009bSShunqian Zheng 	v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
11868a77009bSShunqian Zheng 			  0, OV5695_PIXEL_RATE, 1, OV5695_PIXEL_RATE);
11878a77009bSShunqian Zheng 
11888a77009bSShunqian Zheng 	h_blank = mode->hts_def - mode->width;
11898a77009bSShunqian Zheng 	ov5695->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
11908a77009bSShunqian Zheng 				h_blank, h_blank, 1, h_blank);
11918a77009bSShunqian Zheng 	if (ov5695->hblank)
11928a77009bSShunqian Zheng 		ov5695->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
11938a77009bSShunqian Zheng 
11948a77009bSShunqian Zheng 	vblank_def = mode->vts_def - mode->height;
11958a77009bSShunqian Zheng 	ov5695->vblank = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
11968a77009bSShunqian Zheng 				V4L2_CID_VBLANK, vblank_def,
11978a77009bSShunqian Zheng 				OV5695_VTS_MAX - mode->height,
11988a77009bSShunqian Zheng 				1, vblank_def);
11998a77009bSShunqian Zheng 
12008a77009bSShunqian Zheng 	exposure_max = mode->vts_def - 4;
12018a77009bSShunqian Zheng 	ov5695->exposure = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
12028a77009bSShunqian Zheng 				V4L2_CID_EXPOSURE, OV5695_EXPOSURE_MIN,
12038a77009bSShunqian Zheng 				exposure_max, OV5695_EXPOSURE_STEP,
12048a77009bSShunqian Zheng 				mode->exp_def);
12058a77009bSShunqian Zheng 
12068a77009bSShunqian Zheng 	ov5695->anal_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
12078a77009bSShunqian Zheng 				V4L2_CID_ANALOGUE_GAIN, ANALOG_GAIN_MIN,
12088a77009bSShunqian Zheng 				ANALOG_GAIN_MAX, ANALOG_GAIN_STEP,
12098a77009bSShunqian Zheng 				ANALOG_GAIN_DEFAULT);
12108a77009bSShunqian Zheng 
12118a77009bSShunqian Zheng 	/* Digital gain */
12128a77009bSShunqian Zheng 	ov5695->digi_gain = v4l2_ctrl_new_std(handler, &ov5695_ctrl_ops,
12138a77009bSShunqian Zheng 				V4L2_CID_DIGITAL_GAIN, OV5695_DIGI_GAIN_MIN,
12148a77009bSShunqian Zheng 				OV5695_DIGI_GAIN_MAX, OV5695_DIGI_GAIN_STEP,
12158a77009bSShunqian Zheng 				OV5695_DIGI_GAIN_DEFAULT);
12168a77009bSShunqian Zheng 
12178a77009bSShunqian Zheng 	ov5695->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
12188a77009bSShunqian Zheng 				&ov5695_ctrl_ops, V4L2_CID_TEST_PATTERN,
12198a77009bSShunqian Zheng 				ARRAY_SIZE(ov5695_test_pattern_menu) - 1,
12208a77009bSShunqian Zheng 				0, 0, ov5695_test_pattern_menu);
12218a77009bSShunqian Zheng 
12228a77009bSShunqian Zheng 	if (handler->error) {
12238a77009bSShunqian Zheng 		ret = handler->error;
12248a77009bSShunqian Zheng 		dev_err(&ov5695->client->dev,
12258a77009bSShunqian Zheng 			"Failed to init controls(%d)\n", ret);
12268a77009bSShunqian Zheng 		goto err_free_handler;
12278a77009bSShunqian Zheng 	}
12288a77009bSShunqian Zheng 
12298a77009bSShunqian Zheng 	ov5695->subdev.ctrl_handler = handler;
12308a77009bSShunqian Zheng 
12318a77009bSShunqian Zheng 	return 0;
12328a77009bSShunqian Zheng 
12338a77009bSShunqian Zheng err_free_handler:
12348a77009bSShunqian Zheng 	v4l2_ctrl_handler_free(handler);
12358a77009bSShunqian Zheng 
12368a77009bSShunqian Zheng 	return ret;
12378a77009bSShunqian Zheng }
12388a77009bSShunqian Zheng 
ov5695_check_sensor_id(struct ov5695 * ov5695,struct i2c_client * client)12398a77009bSShunqian Zheng static int ov5695_check_sensor_id(struct ov5695 *ov5695,
12408a77009bSShunqian Zheng 				  struct i2c_client *client)
12418a77009bSShunqian Zheng {
12428a77009bSShunqian Zheng 	struct device *dev = &ov5695->client->dev;
12438a77009bSShunqian Zheng 	u32 id = 0;
12448a77009bSShunqian Zheng 	int ret;
12458a77009bSShunqian Zheng 
12468a77009bSShunqian Zheng 	ret = ov5695_read_reg(client, OV5695_REG_CHIP_ID,
12478a77009bSShunqian Zheng 			      OV5695_REG_VALUE_24BIT, &id);
12488a77009bSShunqian Zheng 	if (id != CHIP_ID) {
12498a77009bSShunqian Zheng 		dev_err(dev, "Unexpected sensor id(%06x), ret(%d)\n", id, ret);
12508a77009bSShunqian Zheng 		return ret;
12518a77009bSShunqian Zheng 	}
12528a77009bSShunqian Zheng 
12538a77009bSShunqian Zheng 	dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
12548a77009bSShunqian Zheng 
12558a77009bSShunqian Zheng 	return 0;
12568a77009bSShunqian Zheng }
12578a77009bSShunqian Zheng 
ov5695_configure_regulators(struct ov5695 * ov5695)12588a77009bSShunqian Zheng static int ov5695_configure_regulators(struct ov5695 *ov5695)
12598a77009bSShunqian Zheng {
12608a77009bSShunqian Zheng 	int i;
12618a77009bSShunqian Zheng 
12628a77009bSShunqian Zheng 	for (i = 0; i < OV5695_NUM_SUPPLIES; i++)
12638a77009bSShunqian Zheng 		ov5695->supplies[i].supply = ov5695_supply_names[i];
12648a77009bSShunqian Zheng 
12658a77009bSShunqian Zheng 	return devm_regulator_bulk_get(&ov5695->client->dev,
12668a77009bSShunqian Zheng 				       OV5695_NUM_SUPPLIES,
12678a77009bSShunqian Zheng 				       ov5695->supplies);
12688a77009bSShunqian Zheng }
12698a77009bSShunqian Zheng 
ov5695_probe(struct i2c_client * client)127079e070c5SUwe Kleine-König static int ov5695_probe(struct i2c_client *client)
12718a77009bSShunqian Zheng {
12728a77009bSShunqian Zheng 	struct device *dev = &client->dev;
12738a77009bSShunqian Zheng 	struct ov5695 *ov5695;
12748a77009bSShunqian Zheng 	struct v4l2_subdev *sd;
12758a77009bSShunqian Zheng 	int ret;
12768a77009bSShunqian Zheng 
12778a77009bSShunqian Zheng 	ov5695 = devm_kzalloc(dev, sizeof(*ov5695), GFP_KERNEL);
12788a77009bSShunqian Zheng 	if (!ov5695)
12798a77009bSShunqian Zheng 		return -ENOMEM;
12808a77009bSShunqian Zheng 
12818a77009bSShunqian Zheng 	ov5695->client = client;
12828a77009bSShunqian Zheng 	ov5695->cur_mode = &supported_modes[0];
12838a77009bSShunqian Zheng 
12848a77009bSShunqian Zheng 	ov5695->xvclk = devm_clk_get(dev, "xvclk");
12858a77009bSShunqian Zheng 	if (IS_ERR(ov5695->xvclk)) {
12868a77009bSShunqian Zheng 		dev_err(dev, "Failed to get xvclk\n");
12878a77009bSShunqian Zheng 		return -EINVAL;
12888a77009bSShunqian Zheng 	}
12898a77009bSShunqian Zheng 	ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ);
12908a77009bSShunqian Zheng 	if (ret < 0) {
12918a77009bSShunqian Zheng 		dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
12928a77009bSShunqian Zheng 		return ret;
12938a77009bSShunqian Zheng 	}
12948a77009bSShunqian Zheng 	if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ)
12958a77009bSShunqian Zheng 		dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
12968a77009bSShunqian Zheng 
1297f1a64f56SDongchun Zhu 	ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
12988a77009bSShunqian Zheng 	if (IS_ERR(ov5695->reset_gpio)) {
12998a77009bSShunqian Zheng 		dev_err(dev, "Failed to get reset-gpios\n");
13008a77009bSShunqian Zheng 		return -EINVAL;
13018a77009bSShunqian Zheng 	}
13028a77009bSShunqian Zheng 
13038a77009bSShunqian Zheng 	ret = ov5695_configure_regulators(ov5695);
13048a77009bSShunqian Zheng 	if (ret) {
13058a77009bSShunqian Zheng 		dev_err(dev, "Failed to get power regulators\n");
13068a77009bSShunqian Zheng 		return ret;
13078a77009bSShunqian Zheng 	}
13088a77009bSShunqian Zheng 
13098a77009bSShunqian Zheng 	mutex_init(&ov5695->mutex);
13108a77009bSShunqian Zheng 
13118a77009bSShunqian Zheng 	sd = &ov5695->subdev;
13128a77009bSShunqian Zheng 	v4l2_i2c_subdev_init(sd, client, &ov5695_subdev_ops);
13138a77009bSShunqian Zheng 	ret = ov5695_initialize_controls(ov5695);
13148a77009bSShunqian Zheng 	if (ret)
13158a77009bSShunqian Zheng 		goto err_destroy_mutex;
13168a77009bSShunqian Zheng 
13178a77009bSShunqian Zheng 	ret = __ov5695_power_on(ov5695);
13188a77009bSShunqian Zheng 	if (ret)
13198a77009bSShunqian Zheng 		goto err_free_handler;
13208a77009bSShunqian Zheng 
13218a77009bSShunqian Zheng 	ret = ov5695_check_sensor_id(ov5695, client);
13228a77009bSShunqian Zheng 	if (ret)
13238a77009bSShunqian Zheng 		goto err_power_off;
13248a77009bSShunqian Zheng 
13258a77009bSShunqian Zheng #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
13268a77009bSShunqian Zheng 	sd->internal_ops = &ov5695_internal_ops;
13278a77009bSShunqian Zheng 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
13288a77009bSShunqian Zheng #endif
13298a77009bSShunqian Zheng #if defined(CONFIG_MEDIA_CONTROLLER)
13308a77009bSShunqian Zheng 	ov5695->pad.flags = MEDIA_PAD_FL_SOURCE;
13318a77009bSShunqian Zheng 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
13328a77009bSShunqian Zheng 	ret = media_entity_pads_init(&sd->entity, 1, &ov5695->pad);
13338a77009bSShunqian Zheng 	if (ret < 0)
13348a77009bSShunqian Zheng 		goto err_power_off;
13358a77009bSShunqian Zheng #endif
13368a77009bSShunqian Zheng 
133715786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(sd);
13388a77009bSShunqian Zheng 	if (ret) {
13398a77009bSShunqian Zheng 		dev_err(dev, "v4l2 async register subdev failed\n");
13408a77009bSShunqian Zheng 		goto err_clean_entity;
13418a77009bSShunqian Zheng 	}
13428a77009bSShunqian Zheng 
13438a77009bSShunqian Zheng 	pm_runtime_set_active(dev);
13448a77009bSShunqian Zheng 	pm_runtime_enable(dev);
13458a77009bSShunqian Zheng 	pm_runtime_idle(dev);
13468a77009bSShunqian Zheng 
13478a77009bSShunqian Zheng 	return 0;
13488a77009bSShunqian Zheng 
13498a77009bSShunqian Zheng err_clean_entity:
13508a77009bSShunqian Zheng #if defined(CONFIG_MEDIA_CONTROLLER)
13518a77009bSShunqian Zheng 	media_entity_cleanup(&sd->entity);
13528a77009bSShunqian Zheng #endif
13538a77009bSShunqian Zheng err_power_off:
13548a77009bSShunqian Zheng 	__ov5695_power_off(ov5695);
13558a77009bSShunqian Zheng err_free_handler:
13568a77009bSShunqian Zheng 	v4l2_ctrl_handler_free(&ov5695->ctrl_handler);
13578a77009bSShunqian Zheng err_destroy_mutex:
13588a77009bSShunqian Zheng 	mutex_destroy(&ov5695->mutex);
13598a77009bSShunqian Zheng 
13608a77009bSShunqian Zheng 	return ret;
13618a77009bSShunqian Zheng }
13628a77009bSShunqian Zheng 
ov5695_remove(struct i2c_client * client)1363ed5c2f5fSUwe Kleine-König static void ov5695_remove(struct i2c_client *client)
13648a77009bSShunqian Zheng {
13658a77009bSShunqian Zheng 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
13668a77009bSShunqian Zheng 	struct ov5695 *ov5695 = to_ov5695(sd);
13678a77009bSShunqian Zheng 
13688a77009bSShunqian Zheng 	v4l2_async_unregister_subdev(sd);
13698a77009bSShunqian Zheng #if defined(CONFIG_MEDIA_CONTROLLER)
13708a77009bSShunqian Zheng 	media_entity_cleanup(&sd->entity);
13718a77009bSShunqian Zheng #endif
13728a77009bSShunqian Zheng 	v4l2_ctrl_handler_free(&ov5695->ctrl_handler);
13738a77009bSShunqian Zheng 	mutex_destroy(&ov5695->mutex);
13748a77009bSShunqian Zheng 
13758a77009bSShunqian Zheng 	pm_runtime_disable(&client->dev);
13768a77009bSShunqian Zheng 	if (!pm_runtime_status_suspended(&client->dev))
13778a77009bSShunqian Zheng 		__ov5695_power_off(ov5695);
13788a77009bSShunqian Zheng 	pm_runtime_set_suspended(&client->dev);
13798a77009bSShunqian Zheng }
13808a77009bSShunqian Zheng 
13818a77009bSShunqian Zheng #if IS_ENABLED(CONFIG_OF)
13828a77009bSShunqian Zheng static const struct of_device_id ov5695_of_match[] = {
13838a77009bSShunqian Zheng 	{ .compatible = "ovti,ov5695" },
13848a77009bSShunqian Zheng 	{},
13858a77009bSShunqian Zheng };
13868a77009bSShunqian Zheng MODULE_DEVICE_TABLE(of, ov5695_of_match);
13878a77009bSShunqian Zheng #endif
13888a77009bSShunqian Zheng 
13898a77009bSShunqian Zheng static struct i2c_driver ov5695_i2c_driver = {
13908a77009bSShunqian Zheng 	.driver = {
13918a77009bSShunqian Zheng 		.name = "ov5695",
13928a77009bSShunqian Zheng 		.pm = &ov5695_pm_ops,
13938a77009bSShunqian Zheng 		.of_match_table = of_match_ptr(ov5695_of_match),
13948a77009bSShunqian Zheng 	},
1395*aaeb31c0SUwe Kleine-König 	.probe		= ov5695_probe,
1396*aaeb31c0SUwe Kleine-König 	.remove		= ov5695_remove,
13978a77009bSShunqian Zheng };
13988a77009bSShunqian Zheng 
13998a77009bSShunqian Zheng module_i2c_driver(ov5695_i2c_driver);
14008a77009bSShunqian Zheng 
14018a77009bSShunqian Zheng MODULE_DESCRIPTION("OmniVision ov5695 sensor driver");
14028a77009bSShunqian Zheng MODULE_LICENSE("GPL v2");
1403