18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ov2685 driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/clk.h>
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
168c2ecf20Sopenharmony_ci#include <linux/sysfs.h>
178c2ecf20Sopenharmony_ci#include <media/media-entity.h>
188c2ecf20Sopenharmony_ci#include <media/v4l2-async.h>
198c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h>
208c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define CHIP_ID				0x2685
238c2ecf20Sopenharmony_ci#define OV2685_REG_CHIP_ID		0x300a
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define OV2685_XVCLK_FREQ		24000000
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define REG_SC_CTRL_MODE		0x0100
288c2ecf20Sopenharmony_ci#define     SC_CTRL_MODE_STANDBY	0x0
298c2ecf20Sopenharmony_ci#define     SC_CTRL_MODE_STREAMING	BIT(0)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define OV2685_REG_EXPOSURE		0x3500
328c2ecf20Sopenharmony_ci#define	OV2685_EXPOSURE_MIN		4
338c2ecf20Sopenharmony_ci#define	OV2685_EXPOSURE_STEP		1
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define OV2685_REG_VTS			0x380e
368c2ecf20Sopenharmony_ci#define OV2685_VTS_MAX			0x7fff
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define OV2685_REG_GAIN			0x350a
398c2ecf20Sopenharmony_ci#define OV2685_GAIN_MIN			0
408c2ecf20Sopenharmony_ci#define OV2685_GAIN_MAX			0x07ff
418c2ecf20Sopenharmony_ci#define OV2685_GAIN_STEP		0x1
428c2ecf20Sopenharmony_ci#define OV2685_GAIN_DEFAULT		0x0036
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define OV2685_REG_TEST_PATTERN		0x5080
458c2ecf20Sopenharmony_ci#define OV2685_TEST_PATTERN_DISABLED		0x00
468c2ecf20Sopenharmony_ci#define OV2685_TEST_PATTERN_COLOR_BAR		0x80
478c2ecf20Sopenharmony_ci#define OV2685_TEST_PATTERN_RANDOM		0x81
488c2ecf20Sopenharmony_ci#define OV2685_TEST_PATTERN_COLOR_BAR_FADE	0x88
498c2ecf20Sopenharmony_ci#define OV2685_TEST_PATTERN_BW_SQUARE		0x92
508c2ecf20Sopenharmony_ci#define OV2685_TEST_PATTERN_COLOR_SQUARE	0x82
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define REG_NULL			0xFFFF
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define OV2685_REG_VALUE_08BIT		1
558c2ecf20Sopenharmony_ci#define OV2685_REG_VALUE_16BIT		2
568c2ecf20Sopenharmony_ci#define OV2685_REG_VALUE_24BIT		3
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define OV2685_LANES			1
598c2ecf20Sopenharmony_ci#define OV2685_BITS_PER_SAMPLE		10
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic const char * const ov2685_supply_names[] = {
628c2ecf20Sopenharmony_ci	"avdd",		/* Analog power */
638c2ecf20Sopenharmony_ci	"dovdd",	/* Digital I/O power */
648c2ecf20Sopenharmony_ci	"dvdd",		/* Digital core power */
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define OV2685_NUM_SUPPLIES ARRAY_SIZE(ov2685_supply_names)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct regval {
708c2ecf20Sopenharmony_ci	u16 addr;
718c2ecf20Sopenharmony_ci	u8 val;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistruct ov2685_mode {
758c2ecf20Sopenharmony_ci	u32 width;
768c2ecf20Sopenharmony_ci	u32 height;
778c2ecf20Sopenharmony_ci	u32 exp_def;
788c2ecf20Sopenharmony_ci	u32 hts_def;
798c2ecf20Sopenharmony_ci	u32 vts_def;
808c2ecf20Sopenharmony_ci	const struct regval *reg_list;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistruct ov2685 {
848c2ecf20Sopenharmony_ci	struct i2c_client	*client;
858c2ecf20Sopenharmony_ci	struct clk		*xvclk;
868c2ecf20Sopenharmony_ci	struct gpio_desc	*reset_gpio;
878c2ecf20Sopenharmony_ci	struct regulator_bulk_data supplies[OV2685_NUM_SUPPLIES];
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	bool			streaming;
908c2ecf20Sopenharmony_ci	struct mutex		mutex;
918c2ecf20Sopenharmony_ci	struct v4l2_subdev	subdev;
928c2ecf20Sopenharmony_ci	struct media_pad	pad;
938c2ecf20Sopenharmony_ci	struct v4l2_ctrl	*anal_gain;
948c2ecf20Sopenharmony_ci	struct v4l2_ctrl	*exposure;
958c2ecf20Sopenharmony_ci	struct v4l2_ctrl	*hblank;
968c2ecf20Sopenharmony_ci	struct v4l2_ctrl	*vblank;
978c2ecf20Sopenharmony_ci	struct v4l2_ctrl	*test_pattern;
988c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler ctrl_handler;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	const struct ov2685_mode *cur_mode;
1018c2ecf20Sopenharmony_ci};
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define to_ov2685(sd) container_of(sd, struct ov2685, subdev)
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* PLL settings bases on 24M xvclk */
1068c2ecf20Sopenharmony_cistatic struct regval ov2685_1600x1200_regs[] = {
1078c2ecf20Sopenharmony_ci	{0x0103, 0x01},
1088c2ecf20Sopenharmony_ci	{0x0100, 0x00},
1098c2ecf20Sopenharmony_ci	{0x3002, 0x00},
1108c2ecf20Sopenharmony_ci	{0x3016, 0x1c},
1118c2ecf20Sopenharmony_ci	{0x3018, 0x44},
1128c2ecf20Sopenharmony_ci	{0x301d, 0xf0},
1138c2ecf20Sopenharmony_ci	{0x3020, 0x00},
1148c2ecf20Sopenharmony_ci	{0x3082, 0x37},
1158c2ecf20Sopenharmony_ci	{0x3083, 0x03},
1168c2ecf20Sopenharmony_ci	{0x3084, 0x09},
1178c2ecf20Sopenharmony_ci	{0x3085, 0x04},
1188c2ecf20Sopenharmony_ci	{0x3086, 0x00},
1198c2ecf20Sopenharmony_ci	{0x3087, 0x00},
1208c2ecf20Sopenharmony_ci	{0x3501, 0x4e},
1218c2ecf20Sopenharmony_ci	{0x3502, 0xe0},
1228c2ecf20Sopenharmony_ci	{0x3503, 0x27},
1238c2ecf20Sopenharmony_ci	{0x350b, 0x36},
1248c2ecf20Sopenharmony_ci	{0x3600, 0xb4},
1258c2ecf20Sopenharmony_ci	{0x3603, 0x35},
1268c2ecf20Sopenharmony_ci	{0x3604, 0x24},
1278c2ecf20Sopenharmony_ci	{0x3605, 0x00},
1288c2ecf20Sopenharmony_ci	{0x3620, 0x24},
1298c2ecf20Sopenharmony_ci	{0x3621, 0x34},
1308c2ecf20Sopenharmony_ci	{0x3622, 0x03},
1318c2ecf20Sopenharmony_ci	{0x3628, 0x10},
1328c2ecf20Sopenharmony_ci	{0x3705, 0x3c},
1338c2ecf20Sopenharmony_ci	{0x370a, 0x21},
1348c2ecf20Sopenharmony_ci	{0x370c, 0x50},
1358c2ecf20Sopenharmony_ci	{0x370d, 0xc0},
1368c2ecf20Sopenharmony_ci	{0x3717, 0x58},
1378c2ecf20Sopenharmony_ci	{0x3718, 0x80},
1388c2ecf20Sopenharmony_ci	{0x3720, 0x00},
1398c2ecf20Sopenharmony_ci	{0x3721, 0x09},
1408c2ecf20Sopenharmony_ci	{0x3722, 0x06},
1418c2ecf20Sopenharmony_ci	{0x3723, 0x59},
1428c2ecf20Sopenharmony_ci	{0x3738, 0x99},
1438c2ecf20Sopenharmony_ci	{0x3781, 0x80},
1448c2ecf20Sopenharmony_ci	{0x3784, 0x0c},
1458c2ecf20Sopenharmony_ci	{0x3789, 0x60},
1468c2ecf20Sopenharmony_ci	{0x3800, 0x00},
1478c2ecf20Sopenharmony_ci	{0x3801, 0x00},
1488c2ecf20Sopenharmony_ci	{0x3802, 0x00},
1498c2ecf20Sopenharmony_ci	{0x3803, 0x00},
1508c2ecf20Sopenharmony_ci	{0x3804, 0x06},
1518c2ecf20Sopenharmony_ci	{0x3805, 0x4f},
1528c2ecf20Sopenharmony_ci	{0x3806, 0x04},
1538c2ecf20Sopenharmony_ci	{0x3807, 0xbf},
1548c2ecf20Sopenharmony_ci	{0x3808, 0x06},
1558c2ecf20Sopenharmony_ci	{0x3809, 0x40},
1568c2ecf20Sopenharmony_ci	{0x380a, 0x04},
1578c2ecf20Sopenharmony_ci	{0x380b, 0xb0},
1588c2ecf20Sopenharmony_ci	{0x380c, 0x06},
1598c2ecf20Sopenharmony_ci	{0x380d, 0xa4},
1608c2ecf20Sopenharmony_ci	{0x380e, 0x05},
1618c2ecf20Sopenharmony_ci	{0x380f, 0x0e},
1628c2ecf20Sopenharmony_ci	{0x3810, 0x00},
1638c2ecf20Sopenharmony_ci	{0x3811, 0x08},
1648c2ecf20Sopenharmony_ci	{0x3812, 0x00},
1658c2ecf20Sopenharmony_ci	{0x3813, 0x08},
1668c2ecf20Sopenharmony_ci	{0x3814, 0x11},
1678c2ecf20Sopenharmony_ci	{0x3815, 0x11},
1688c2ecf20Sopenharmony_ci	{0x3819, 0x04},
1698c2ecf20Sopenharmony_ci	{0x3820, 0xc0},
1708c2ecf20Sopenharmony_ci	{0x3821, 0x00},
1718c2ecf20Sopenharmony_ci	{0x3a06, 0x01},
1728c2ecf20Sopenharmony_ci	{0x3a07, 0x84},
1738c2ecf20Sopenharmony_ci	{0x3a08, 0x01},
1748c2ecf20Sopenharmony_ci	{0x3a09, 0x43},
1758c2ecf20Sopenharmony_ci	{0x3a0a, 0x24},
1768c2ecf20Sopenharmony_ci	{0x3a0b, 0x60},
1778c2ecf20Sopenharmony_ci	{0x3a0c, 0x28},
1788c2ecf20Sopenharmony_ci	{0x3a0d, 0x60},
1798c2ecf20Sopenharmony_ci	{0x3a0e, 0x04},
1808c2ecf20Sopenharmony_ci	{0x3a0f, 0x8c},
1818c2ecf20Sopenharmony_ci	{0x3a10, 0x05},
1828c2ecf20Sopenharmony_ci	{0x3a11, 0x0c},
1838c2ecf20Sopenharmony_ci	{0x4000, 0x81},
1848c2ecf20Sopenharmony_ci	{0x4001, 0x40},
1858c2ecf20Sopenharmony_ci	{0x4008, 0x02},
1868c2ecf20Sopenharmony_ci	{0x4009, 0x09},
1878c2ecf20Sopenharmony_ci	{0x4300, 0x00},
1888c2ecf20Sopenharmony_ci	{0x430e, 0x00},
1898c2ecf20Sopenharmony_ci	{0x4602, 0x02},
1908c2ecf20Sopenharmony_ci	{0x481b, 0x40},
1918c2ecf20Sopenharmony_ci	{0x481f, 0x40},
1928c2ecf20Sopenharmony_ci	{0x4837, 0x18},
1938c2ecf20Sopenharmony_ci	{0x5000, 0x1f},
1948c2ecf20Sopenharmony_ci	{0x5001, 0x05},
1958c2ecf20Sopenharmony_ci	{0x5002, 0x30},
1968c2ecf20Sopenharmony_ci	{0x5003, 0x04},
1978c2ecf20Sopenharmony_ci	{0x5004, 0x00},
1988c2ecf20Sopenharmony_ci	{0x5005, 0x0c},
1998c2ecf20Sopenharmony_ci	{0x5280, 0x15},
2008c2ecf20Sopenharmony_ci	{0x5281, 0x06},
2018c2ecf20Sopenharmony_ci	{0x5282, 0x06},
2028c2ecf20Sopenharmony_ci	{0x5283, 0x08},
2038c2ecf20Sopenharmony_ci	{0x5284, 0x1c},
2048c2ecf20Sopenharmony_ci	{0x5285, 0x1c},
2058c2ecf20Sopenharmony_ci	{0x5286, 0x20},
2068c2ecf20Sopenharmony_ci	{0x5287, 0x10},
2078c2ecf20Sopenharmony_ci	{REG_NULL, 0x00}
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#define OV2685_LINK_FREQ_330MHZ		330000000
2118c2ecf20Sopenharmony_cistatic const s64 link_freq_menu_items[] = {
2128c2ecf20Sopenharmony_ci	OV2685_LINK_FREQ_330MHZ
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic const char * const ov2685_test_pattern_menu[] = {
2168c2ecf20Sopenharmony_ci	"Disabled",
2178c2ecf20Sopenharmony_ci	"Color Bar",
2188c2ecf20Sopenharmony_ci	"Color Bar FADE",
2198c2ecf20Sopenharmony_ci	"Random Data",
2208c2ecf20Sopenharmony_ci	"Black White Square",
2218c2ecf20Sopenharmony_ci	"Color Square"
2228c2ecf20Sopenharmony_ci};
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic const int ov2685_test_pattern_val[] = {
2258c2ecf20Sopenharmony_ci	OV2685_TEST_PATTERN_DISABLED,
2268c2ecf20Sopenharmony_ci	OV2685_TEST_PATTERN_COLOR_BAR,
2278c2ecf20Sopenharmony_ci	OV2685_TEST_PATTERN_COLOR_BAR_FADE,
2288c2ecf20Sopenharmony_ci	OV2685_TEST_PATTERN_RANDOM,
2298c2ecf20Sopenharmony_ci	OV2685_TEST_PATTERN_BW_SQUARE,
2308c2ecf20Sopenharmony_ci	OV2685_TEST_PATTERN_COLOR_SQUARE,
2318c2ecf20Sopenharmony_ci};
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic const struct ov2685_mode supported_modes[] = {
2348c2ecf20Sopenharmony_ci	{
2358c2ecf20Sopenharmony_ci		.width = 1600,
2368c2ecf20Sopenharmony_ci		.height = 1200,
2378c2ecf20Sopenharmony_ci		.exp_def = 0x04ee,
2388c2ecf20Sopenharmony_ci		.hts_def = 0x06a4,
2398c2ecf20Sopenharmony_ci		.vts_def = 0x050e,
2408c2ecf20Sopenharmony_ci		.reg_list = ov2685_1600x1200_regs,
2418c2ecf20Sopenharmony_ci	},
2428c2ecf20Sopenharmony_ci};
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/* Write registers up to 4 at a time */
2458c2ecf20Sopenharmony_cistatic int ov2685_write_reg(struct i2c_client *client, u16 reg,
2468c2ecf20Sopenharmony_ci			    u32 len, u32 val)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u32 val_i, buf_i;
2498c2ecf20Sopenharmony_ci	u8 buf[6];
2508c2ecf20Sopenharmony_ci	u8 *val_p;
2518c2ecf20Sopenharmony_ci	__be32 val_be;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (len > 4)
2548c2ecf20Sopenharmony_ci		return -EINVAL;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	buf[0] = reg >> 8;
2578c2ecf20Sopenharmony_ci	buf[1] = reg & 0xff;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	val_be = cpu_to_be32(val);
2608c2ecf20Sopenharmony_ci	val_p = (u8 *)&val_be;
2618c2ecf20Sopenharmony_ci	buf_i = 2;
2628c2ecf20Sopenharmony_ci	val_i = 4 - len;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	while (val_i < 4)
2658c2ecf20Sopenharmony_ci		buf[buf_i++] = val_p[val_i++];
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (i2c_master_send(client, buf, len + 2) != len + 2)
2688c2ecf20Sopenharmony_ci		return -EIO;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int ov2685_write_array(struct i2c_client *client,
2748c2ecf20Sopenharmony_ci			      const struct regval *regs)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int ret = 0;
2778c2ecf20Sopenharmony_ci	u32 i;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
2808c2ecf20Sopenharmony_ci		ret = ov2685_write_reg(client, regs[i].addr,
2818c2ecf20Sopenharmony_ci				       OV2685_REG_VALUE_08BIT, regs[i].val);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return ret;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/* Read registers up to 4 at a time */
2878c2ecf20Sopenharmony_cistatic int ov2685_read_reg(struct i2c_client *client, u16 reg,
2888c2ecf20Sopenharmony_ci			   u32 len, u32 *val)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	struct i2c_msg msgs[2];
2918c2ecf20Sopenharmony_ci	u8 *data_be_p;
2928c2ecf20Sopenharmony_ci	__be32 data_be = 0;
2938c2ecf20Sopenharmony_ci	__be16 reg_addr_be = cpu_to_be16(reg);
2948c2ecf20Sopenharmony_ci	int ret;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (len > 4)
2978c2ecf20Sopenharmony_ci		return -EINVAL;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	data_be_p = (u8 *)&data_be;
3008c2ecf20Sopenharmony_ci	/* Write register address */
3018c2ecf20Sopenharmony_ci	msgs[0].addr = client->addr;
3028c2ecf20Sopenharmony_ci	msgs[0].flags = 0;
3038c2ecf20Sopenharmony_ci	msgs[0].len = 2;
3048c2ecf20Sopenharmony_ci	msgs[0].buf = (u8 *)&reg_addr_be;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* Read data from register */
3078c2ecf20Sopenharmony_ci	msgs[1].addr = client->addr;
3088c2ecf20Sopenharmony_ci	msgs[1].flags = I2C_M_RD;
3098c2ecf20Sopenharmony_ci	msgs[1].len = len;
3108c2ecf20Sopenharmony_ci	msgs[1].buf = &data_be_p[4 - len];
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
3138c2ecf20Sopenharmony_ci	if (ret != ARRAY_SIZE(msgs))
3148c2ecf20Sopenharmony_ci		return -EIO;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	*val = be32_to_cpu(data_be);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return 0;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic void ov2685_fill_fmt(const struct ov2685_mode *mode,
3228c2ecf20Sopenharmony_ci			    struct v4l2_mbus_framefmt *fmt)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
3258c2ecf20Sopenharmony_ci	fmt->width = mode->width;
3268c2ecf20Sopenharmony_ci	fmt->height = mode->height;
3278c2ecf20Sopenharmony_ci	fmt->field = V4L2_FIELD_NONE;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int ov2685_set_fmt(struct v4l2_subdev *sd,
3318c2ecf20Sopenharmony_ci			  struct v4l2_subdev_pad_config *cfg,
3328c2ecf20Sopenharmony_ci			  struct v4l2_subdev_format *fmt)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
3358c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* only one mode supported for now */
3388c2ecf20Sopenharmony_ci	ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return 0;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int ov2685_get_fmt(struct v4l2_subdev *sd,
3448c2ecf20Sopenharmony_ci			  struct v4l2_subdev_pad_config *cfg,
3458c2ecf20Sopenharmony_ci			  struct v4l2_subdev_format *fmt)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
3488c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	ov2685_fill_fmt(ov2685->cur_mode, mbus_fmt);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return 0;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic int ov2685_enum_mbus_code(struct v4l2_subdev *sd,
3568c2ecf20Sopenharmony_ci				 struct v4l2_subdev_pad_config *cfg,
3578c2ecf20Sopenharmony_ci				 struct v4l2_subdev_mbus_code_enum *code)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	if (code->index >= ARRAY_SIZE(supported_modes))
3608c2ecf20Sopenharmony_ci		return -EINVAL;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return 0;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic int ov2685_enum_frame_sizes(struct v4l2_subdev *sd,
3688c2ecf20Sopenharmony_ci				   struct v4l2_subdev_pad_config *cfg,
3698c2ecf20Sopenharmony_ci				   struct v4l2_subdev_frame_size_enum *fse)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	int index = fse->index;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (index >= ARRAY_SIZE(supported_modes))
3748c2ecf20Sopenharmony_ci		return -EINVAL;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	fse->code = MEDIA_BUS_FMT_SBGGR10_1X10;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	fse->min_width  = supported_modes[index].width;
3798c2ecf20Sopenharmony_ci	fse->max_width  = supported_modes[index].width;
3808c2ecf20Sopenharmony_ci	fse->max_height = supported_modes[index].height;
3818c2ecf20Sopenharmony_ci	fse->min_height = supported_modes[index].height;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return 0;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/* Calculate the delay in us by clock rate and clock cycles */
3878c2ecf20Sopenharmony_cistatic inline u32 ov2685_cal_delay(u32 cycles)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(cycles, OV2685_XVCLK_FREQ / 1000 / 1000);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int __ov2685_power_on(struct ov2685 *ov2685)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	int ret;
3958c2ecf20Sopenharmony_ci	u32 delay_us;
3968c2ecf20Sopenharmony_ci	struct device *dev = &ov2685->client->dev;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(ov2685->xvclk);
3998c2ecf20Sopenharmony_ci	if (ret < 0) {
4008c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to enable xvclk\n");
4018c2ecf20Sopenharmony_ci		return ret;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(OV2685_NUM_SUPPLIES, ov2685->supplies);
4078c2ecf20Sopenharmony_ci	if (ret < 0) {
4088c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to enable regulators\n");
4098c2ecf20Sopenharmony_ci		goto disable_clk;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* The minimum delay between power supplies and reset rising can be 0 */
4138c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(ov2685->reset_gpio, 0);
4148c2ecf20Sopenharmony_ci	/* 8192 xvclk cycles prior to the first SCCB transaction */
4158c2ecf20Sopenharmony_ci	delay_us = ov2685_cal_delay(8192);
4168c2ecf20Sopenharmony_ci	usleep_range(delay_us, delay_us * 2);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* HACK: ov2685 would output messy data after reset(R0103),
4198c2ecf20Sopenharmony_ci	 * writing register before .s_stream() as a workaround
4208c2ecf20Sopenharmony_ci	 */
4218c2ecf20Sopenharmony_ci	ret = ov2685_write_array(ov2685->client, ov2685->cur_mode->reg_list);
4228c2ecf20Sopenharmony_ci	if (ret)
4238c2ecf20Sopenharmony_ci		goto disable_supplies;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cidisable_supplies:
4288c2ecf20Sopenharmony_ci	regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
4298c2ecf20Sopenharmony_cidisable_clk:
4308c2ecf20Sopenharmony_ci	clk_disable_unprepare(ov2685->xvclk);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return ret;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic void __ov2685_power_off(struct ov2685 *ov2685)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	/* 512 xvclk cycles after the last SCCB transaction or MIPI frame end */
4388c2ecf20Sopenharmony_ci	u32 delay_us = ov2685_cal_delay(512);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	usleep_range(delay_us, delay_us * 2);
4418c2ecf20Sopenharmony_ci	clk_disable_unprepare(ov2685->xvclk);
4428c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(ov2685->reset_gpio, 1);
4438c2ecf20Sopenharmony_ci	regulator_bulk_disable(OV2685_NUM_SUPPLIES, ov2685->supplies);
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_cistatic int ov2685_s_stream(struct v4l2_subdev *sd, int on)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
4498c2ecf20Sopenharmony_ci	struct i2c_client *client = ov2685->client;
4508c2ecf20Sopenharmony_ci	int ret = 0;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	mutex_lock(&ov2685->mutex);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	on = !!on;
4558c2ecf20Sopenharmony_ci	if (on == ov2685->streaming)
4568c2ecf20Sopenharmony_ci		goto unlock_and_return;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (on) {
4598c2ecf20Sopenharmony_ci		ret = pm_runtime_get_sync(&ov2685->client->dev);
4608c2ecf20Sopenharmony_ci		if (ret < 0) {
4618c2ecf20Sopenharmony_ci			pm_runtime_put_noidle(&client->dev);
4628c2ecf20Sopenharmony_ci			goto unlock_and_return;
4638c2ecf20Sopenharmony_ci		}
4648c2ecf20Sopenharmony_ci		ret = __v4l2_ctrl_handler_setup(&ov2685->ctrl_handler);
4658c2ecf20Sopenharmony_ci		if (ret) {
4668c2ecf20Sopenharmony_ci			pm_runtime_put(&client->dev);
4678c2ecf20Sopenharmony_ci			goto unlock_and_return;
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci		ret = ov2685_write_reg(client, REG_SC_CTRL_MODE,
4708c2ecf20Sopenharmony_ci				OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STREAMING);
4718c2ecf20Sopenharmony_ci		if (ret) {
4728c2ecf20Sopenharmony_ci			pm_runtime_put(&client->dev);
4738c2ecf20Sopenharmony_ci			goto unlock_and_return;
4748c2ecf20Sopenharmony_ci		}
4758c2ecf20Sopenharmony_ci	} else {
4768c2ecf20Sopenharmony_ci		ov2685_write_reg(client, REG_SC_CTRL_MODE,
4778c2ecf20Sopenharmony_ci				OV2685_REG_VALUE_08BIT, SC_CTRL_MODE_STANDBY);
4788c2ecf20Sopenharmony_ci		pm_runtime_put(&ov2685->client->dev);
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	ov2685->streaming = on;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ciunlock_and_return:
4848c2ecf20Sopenharmony_ci	mutex_unlock(&ov2685->mutex);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	return ret;
4878c2ecf20Sopenharmony_ci}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
4908c2ecf20Sopenharmony_cistatic int ov2685_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
4938c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *try_fmt;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	mutex_lock(&ov2685->mutex);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, 0);
4988c2ecf20Sopenharmony_ci	/* Initialize try_fmt */
4998c2ecf20Sopenharmony_ci	ov2685_fill_fmt(&supported_modes[0], try_fmt);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	mutex_unlock(&ov2685->mutex);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	return 0;
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci#endif
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_cistatic int __maybe_unused ov2685_runtime_resume(struct device *dev)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5108c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
5118c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	return __ov2685_power_on(ov2685);
5148c2ecf20Sopenharmony_ci}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_cistatic int __maybe_unused ov2685_runtime_suspend(struct device *dev)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
5198c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
5208c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	__ov2685_power_off(ov2685);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return 0;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic const struct dev_pm_ops ov2685_pm_ops = {
5288c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(ov2685_runtime_suspend,
5298c2ecf20Sopenharmony_ci			   ov2685_runtime_resume, NULL)
5308c2ecf20Sopenharmony_ci};
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic int ov2685_set_ctrl(struct v4l2_ctrl *ctrl)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = container_of(ctrl->handler,
5358c2ecf20Sopenharmony_ci					     struct ov2685, ctrl_handler);
5368c2ecf20Sopenharmony_ci	struct i2c_client *client = ov2685->client;
5378c2ecf20Sopenharmony_ci	s64 max_expo;
5388c2ecf20Sopenharmony_ci	int ret;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* Propagate change of current control to all related controls */
5418c2ecf20Sopenharmony_ci	switch (ctrl->id) {
5428c2ecf20Sopenharmony_ci	case V4L2_CID_VBLANK:
5438c2ecf20Sopenharmony_ci		/* Update max exposure while meeting expected vblanking */
5448c2ecf20Sopenharmony_ci		max_expo = ov2685->cur_mode->height + ctrl->val - 4;
5458c2ecf20Sopenharmony_ci		__v4l2_ctrl_modify_range(ov2685->exposure,
5468c2ecf20Sopenharmony_ci					 ov2685->exposure->minimum, max_expo,
5478c2ecf20Sopenharmony_ci					 ov2685->exposure->step,
5488c2ecf20Sopenharmony_ci					 ov2685->exposure->default_value);
5498c2ecf20Sopenharmony_ci		break;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (!pm_runtime_get_if_in_use(&client->dev))
5538c2ecf20Sopenharmony_ci		return 0;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	switch (ctrl->id) {
5568c2ecf20Sopenharmony_ci	case V4L2_CID_EXPOSURE:
5578c2ecf20Sopenharmony_ci		ret = ov2685_write_reg(ov2685->client, OV2685_REG_EXPOSURE,
5588c2ecf20Sopenharmony_ci				       OV2685_REG_VALUE_24BIT, ctrl->val << 4);
5598c2ecf20Sopenharmony_ci		break;
5608c2ecf20Sopenharmony_ci	case V4L2_CID_ANALOGUE_GAIN:
5618c2ecf20Sopenharmony_ci		ret = ov2685_write_reg(ov2685->client, OV2685_REG_GAIN,
5628c2ecf20Sopenharmony_ci				       OV2685_REG_VALUE_16BIT, ctrl->val);
5638c2ecf20Sopenharmony_ci		break;
5648c2ecf20Sopenharmony_ci	case V4L2_CID_VBLANK:
5658c2ecf20Sopenharmony_ci		ret = ov2685_write_reg(ov2685->client, OV2685_REG_VTS,
5668c2ecf20Sopenharmony_ci				       OV2685_REG_VALUE_16BIT,
5678c2ecf20Sopenharmony_ci				       ctrl->val + ov2685->cur_mode->height);
5688c2ecf20Sopenharmony_ci		break;
5698c2ecf20Sopenharmony_ci	case V4L2_CID_TEST_PATTERN:
5708c2ecf20Sopenharmony_ci		ret = ov2685_write_reg(ov2685->client, OV2685_REG_TEST_PATTERN,
5718c2ecf20Sopenharmony_ci				       OV2685_REG_VALUE_08BIT,
5728c2ecf20Sopenharmony_ci				       ov2685_test_pattern_val[ctrl->val]);
5738c2ecf20Sopenharmony_ci		break;
5748c2ecf20Sopenharmony_ci	default:
5758c2ecf20Sopenharmony_ci		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
5768c2ecf20Sopenharmony_ci			 __func__, ctrl->id, ctrl->val);
5778c2ecf20Sopenharmony_ci		ret = -EINVAL;
5788c2ecf20Sopenharmony_ci		break;
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	pm_runtime_put(&client->dev);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	return ret;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops ov2685_video_ops = {
5878c2ecf20Sopenharmony_ci	.s_stream = ov2685_s_stream,
5888c2ecf20Sopenharmony_ci};
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops ov2685_pad_ops = {
5918c2ecf20Sopenharmony_ci	.enum_mbus_code = ov2685_enum_mbus_code,
5928c2ecf20Sopenharmony_ci	.enum_frame_size = ov2685_enum_frame_sizes,
5938c2ecf20Sopenharmony_ci	.get_fmt = ov2685_get_fmt,
5948c2ecf20Sopenharmony_ci	.set_fmt = ov2685_set_fmt,
5958c2ecf20Sopenharmony_ci};
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops ov2685_subdev_ops = {
5988c2ecf20Sopenharmony_ci	.video	= &ov2685_video_ops,
5998c2ecf20Sopenharmony_ci	.pad	= &ov2685_pad_ops,
6008c2ecf20Sopenharmony_ci};
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
6038c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops ov2685_internal_ops = {
6048c2ecf20Sopenharmony_ci	.open = ov2685_open,
6058c2ecf20Sopenharmony_ci};
6068c2ecf20Sopenharmony_ci#endif
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops ov2685_ctrl_ops = {
6098c2ecf20Sopenharmony_ci	.s_ctrl = ov2685_set_ctrl,
6108c2ecf20Sopenharmony_ci};
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_cistatic int ov2685_initialize_controls(struct ov2685 *ov2685)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	const struct ov2685_mode *mode;
6158c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler *handler;
6168c2ecf20Sopenharmony_ci	struct v4l2_ctrl *ctrl;
6178c2ecf20Sopenharmony_ci	u64 exposure_max;
6188c2ecf20Sopenharmony_ci	u32 pixel_rate, h_blank;
6198c2ecf20Sopenharmony_ci	int ret;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	handler = &ov2685->ctrl_handler;
6228c2ecf20Sopenharmony_ci	mode = ov2685->cur_mode;
6238c2ecf20Sopenharmony_ci	ret = v4l2_ctrl_handler_init(handler, 8);
6248c2ecf20Sopenharmony_ci	if (ret)
6258c2ecf20Sopenharmony_ci		return ret;
6268c2ecf20Sopenharmony_ci	handler->lock = &ov2685->mutex;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ,
6298c2ecf20Sopenharmony_ci				      0, 0, link_freq_menu_items);
6308c2ecf20Sopenharmony_ci	if (ctrl)
6318c2ecf20Sopenharmony_ci		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	pixel_rate = (link_freq_menu_items[0] * 2 * OV2685_LANES) /
6348c2ecf20Sopenharmony_ci		     OV2685_BITS_PER_SAMPLE;
6358c2ecf20Sopenharmony_ci	v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE,
6368c2ecf20Sopenharmony_ci			  0, pixel_rate, 1, pixel_rate);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	h_blank = mode->hts_def - mode->width;
6398c2ecf20Sopenharmony_ci	ov2685->hblank = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK,
6408c2ecf20Sopenharmony_ci				h_blank, h_blank, 1, h_blank);
6418c2ecf20Sopenharmony_ci	if (ov2685->hblank)
6428c2ecf20Sopenharmony_ci		ov2685->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	ov2685->vblank = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
6458c2ecf20Sopenharmony_ci				V4L2_CID_VBLANK, mode->vts_def - mode->height,
6468c2ecf20Sopenharmony_ci				OV2685_VTS_MAX - mode->height, 1,
6478c2ecf20Sopenharmony_ci				mode->vts_def - mode->height);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	exposure_max = mode->vts_def - 4;
6508c2ecf20Sopenharmony_ci	ov2685->exposure = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
6518c2ecf20Sopenharmony_ci				V4L2_CID_EXPOSURE, OV2685_EXPOSURE_MIN,
6528c2ecf20Sopenharmony_ci				exposure_max, OV2685_EXPOSURE_STEP,
6538c2ecf20Sopenharmony_ci				mode->exp_def);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	ov2685->anal_gain = v4l2_ctrl_new_std(handler, &ov2685_ctrl_ops,
6568c2ecf20Sopenharmony_ci				V4L2_CID_ANALOGUE_GAIN, OV2685_GAIN_MIN,
6578c2ecf20Sopenharmony_ci				OV2685_GAIN_MAX, OV2685_GAIN_STEP,
6588c2ecf20Sopenharmony_ci				OV2685_GAIN_DEFAULT);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	ov2685->test_pattern = v4l2_ctrl_new_std_menu_items(handler,
6618c2ecf20Sopenharmony_ci				&ov2685_ctrl_ops, V4L2_CID_TEST_PATTERN,
6628c2ecf20Sopenharmony_ci				ARRAY_SIZE(ov2685_test_pattern_menu) - 1,
6638c2ecf20Sopenharmony_ci				0, 0, ov2685_test_pattern_menu);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (handler->error) {
6668c2ecf20Sopenharmony_ci		ret = handler->error;
6678c2ecf20Sopenharmony_ci		dev_err(&ov2685->client->dev,
6688c2ecf20Sopenharmony_ci			"Failed to init controls(%d)\n", ret);
6698c2ecf20Sopenharmony_ci		goto err_free_handler;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	ov2685->subdev.ctrl_handler = handler;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	return 0;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cierr_free_handler:
6778c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(handler);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return ret;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic int ov2685_check_sensor_id(struct ov2685 *ov2685,
6838c2ecf20Sopenharmony_ci				  struct i2c_client *client)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct device *dev = &ov2685->client->dev;
6868c2ecf20Sopenharmony_ci	int ret;
6878c2ecf20Sopenharmony_ci	u32 id = 0;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	ret = ov2685_read_reg(client, OV2685_REG_CHIP_ID,
6908c2ecf20Sopenharmony_ci			      OV2685_REG_VALUE_16BIT, &id);
6918c2ecf20Sopenharmony_ci	if (id != CHIP_ID) {
6928c2ecf20Sopenharmony_ci		dev_err(dev, "Unexpected sensor id(%04x), ret(%d)\n", id, ret);
6938c2ecf20Sopenharmony_ci		return ret;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	dev_info(dev, "Detected OV%04x sensor\n", CHIP_ID);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	return 0;
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_cistatic int ov2685_configure_regulators(struct ov2685 *ov2685)
7028c2ecf20Sopenharmony_ci{
7038c2ecf20Sopenharmony_ci	int i;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	for (i = 0; i < OV2685_NUM_SUPPLIES; i++)
7068c2ecf20Sopenharmony_ci		ov2685->supplies[i].supply = ov2685_supply_names[i];
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	return devm_regulator_bulk_get(&ov2685->client->dev,
7098c2ecf20Sopenharmony_ci				       OV2685_NUM_SUPPLIES,
7108c2ecf20Sopenharmony_ci				       ov2685->supplies);
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic int ov2685_probe(struct i2c_client *client,
7148c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
7178c2ecf20Sopenharmony_ci	struct ov2685 *ov2685;
7188c2ecf20Sopenharmony_ci	int ret;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	ov2685 = devm_kzalloc(dev, sizeof(*ov2685), GFP_KERNEL);
7218c2ecf20Sopenharmony_ci	if (!ov2685)
7228c2ecf20Sopenharmony_ci		return -ENOMEM;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	ov2685->client = client;
7258c2ecf20Sopenharmony_ci	ov2685->cur_mode = &supported_modes[0];
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	ov2685->xvclk = devm_clk_get(dev, "xvclk");
7288c2ecf20Sopenharmony_ci	if (IS_ERR(ov2685->xvclk)) {
7298c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to get xvclk\n");
7308c2ecf20Sopenharmony_ci		return -EINVAL;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci	ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ);
7338c2ecf20Sopenharmony_ci	if (ret < 0) {
7348c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to set xvclk rate (24MHz)\n");
7358c2ecf20Sopenharmony_ci		return ret;
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci	if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ)
7388c2ecf20Sopenharmony_ci		dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	ov2685->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
7418c2ecf20Sopenharmony_ci	if (IS_ERR(ov2685->reset_gpio)) {
7428c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to get reset-gpios\n");
7438c2ecf20Sopenharmony_ci		return -EINVAL;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	ret = ov2685_configure_regulators(ov2685);
7478c2ecf20Sopenharmony_ci	if (ret) {
7488c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to get power regulators\n");
7498c2ecf20Sopenharmony_ci		return ret;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	mutex_init(&ov2685->mutex);
7538c2ecf20Sopenharmony_ci	v4l2_i2c_subdev_init(&ov2685->subdev, client, &ov2685_subdev_ops);
7548c2ecf20Sopenharmony_ci	ret = ov2685_initialize_controls(ov2685);
7558c2ecf20Sopenharmony_ci	if (ret)
7568c2ecf20Sopenharmony_ci		goto err_destroy_mutex;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	ret = __ov2685_power_on(ov2685);
7598c2ecf20Sopenharmony_ci	if (ret)
7608c2ecf20Sopenharmony_ci		goto err_free_handler;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	ret = ov2685_check_sensor_id(ov2685, client);
7638c2ecf20Sopenharmony_ci	if (ret)
7648c2ecf20Sopenharmony_ci		goto err_power_off;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
7678c2ecf20Sopenharmony_ci	ov2685->subdev.internal_ops = &ov2685_internal_ops;
7688c2ecf20Sopenharmony_ci	ov2685->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
7698c2ecf20Sopenharmony_ci#endif
7708c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
7718c2ecf20Sopenharmony_ci	ov2685->pad.flags = MEDIA_PAD_FL_SOURCE;
7728c2ecf20Sopenharmony_ci	ov2685->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
7738c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&ov2685->subdev.entity, 1, &ov2685->pad);
7748c2ecf20Sopenharmony_ci	if (ret < 0)
7758c2ecf20Sopenharmony_ci		goto err_power_off;
7768c2ecf20Sopenharmony_ci#endif
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ret = v4l2_async_register_subdev(&ov2685->subdev);
7798c2ecf20Sopenharmony_ci	if (ret) {
7808c2ecf20Sopenharmony_ci		dev_err(dev, "v4l2 async register subdev failed\n");
7818c2ecf20Sopenharmony_ci		goto err_clean_entity;
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	pm_runtime_set_active(dev);
7858c2ecf20Sopenharmony_ci	pm_runtime_enable(dev);
7868c2ecf20Sopenharmony_ci	pm_runtime_idle(dev);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	return 0;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cierr_clean_entity:
7918c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
7928c2ecf20Sopenharmony_ci	media_entity_cleanup(&ov2685->subdev.entity);
7938c2ecf20Sopenharmony_ci#endif
7948c2ecf20Sopenharmony_cierr_power_off:
7958c2ecf20Sopenharmony_ci	__ov2685_power_off(ov2685);
7968c2ecf20Sopenharmony_cierr_free_handler:
7978c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
7988c2ecf20Sopenharmony_cierr_destroy_mutex:
7998c2ecf20Sopenharmony_ci	mutex_destroy(&ov2685->mutex);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	return ret;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic int ov2685_remove(struct i2c_client *client)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
8078c2ecf20Sopenharmony_ci	struct ov2685 *ov2685 = to_ov2685(sd);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	v4l2_async_unregister_subdev(sd);
8108c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER)
8118c2ecf20Sopenharmony_ci	media_entity_cleanup(&sd->entity);
8128c2ecf20Sopenharmony_ci#endif
8138c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&ov2685->ctrl_handler);
8148c2ecf20Sopenharmony_ci	mutex_destroy(&ov2685->mutex);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
8178c2ecf20Sopenharmony_ci	if (!pm_runtime_status_suspended(&client->dev))
8188c2ecf20Sopenharmony_ci		__ov2685_power_off(ov2685);
8198c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	return 0;
8228c2ecf20Sopenharmony_ci}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
8258c2ecf20Sopenharmony_cistatic const struct of_device_id ov2685_of_match[] = {
8268c2ecf20Sopenharmony_ci	{ .compatible = "ovti,ov2685" },
8278c2ecf20Sopenharmony_ci	{},
8288c2ecf20Sopenharmony_ci};
8298c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, ov2685_of_match);
8308c2ecf20Sopenharmony_ci#endif
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_cistatic struct i2c_driver ov2685_i2c_driver = {
8338c2ecf20Sopenharmony_ci	.driver = {
8348c2ecf20Sopenharmony_ci		.name = "ov2685",
8358c2ecf20Sopenharmony_ci		.pm = &ov2685_pm_ops,
8368c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(ov2685_of_match),
8378c2ecf20Sopenharmony_ci	},
8388c2ecf20Sopenharmony_ci	.probe		= &ov2685_probe,
8398c2ecf20Sopenharmony_ci	.remove		= &ov2685_remove,
8408c2ecf20Sopenharmony_ci};
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_cimodule_i2c_driver(ov2685_i2c_driver);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OmniVision ov2685 sensor driver");
8458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
846