xref: /openbmc/linux/drivers/media/i2c/ov4689.c (revision aaeb31c0)
132a437dbSMikhail Rudenko // SPDX-License-Identifier: GPL-2.0
232a437dbSMikhail Rudenko /*
332a437dbSMikhail Rudenko  * ov4689 driver
432a437dbSMikhail Rudenko  *
532a437dbSMikhail Rudenko  * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd.
632a437dbSMikhail Rudenko  * Copyright (C) 2022 Mikhail Rudenko
732a437dbSMikhail Rudenko  */
832a437dbSMikhail Rudenko 
932a437dbSMikhail Rudenko #include <linux/clk.h>
1032a437dbSMikhail Rudenko #include <linux/delay.h>
1132a437dbSMikhail Rudenko #include <linux/gpio/consumer.h>
1232a437dbSMikhail Rudenko #include <linux/i2c.h>
1332a437dbSMikhail Rudenko #include <linux/module.h>
1432a437dbSMikhail Rudenko #include <linux/pm_runtime.h>
1532a437dbSMikhail Rudenko #include <linux/regulator/consumer.h>
1632a437dbSMikhail Rudenko #include <media/media-entity.h>
1732a437dbSMikhail Rudenko #include <media/v4l2-async.h>
1832a437dbSMikhail Rudenko #include <media/v4l2-ctrls.h>
1932a437dbSMikhail Rudenko #include <media/v4l2-subdev.h>
2032a437dbSMikhail Rudenko #include <media/v4l2-fwnode.h>
2132a437dbSMikhail Rudenko 
2232a437dbSMikhail Rudenko #define CHIP_ID				0x004688
2332a437dbSMikhail Rudenko #define OV4689_REG_CHIP_ID		0x300a
2432a437dbSMikhail Rudenko 
2532a437dbSMikhail Rudenko #define OV4689_XVCLK_FREQ		24000000
2632a437dbSMikhail Rudenko 
2732a437dbSMikhail Rudenko #define OV4689_REG_CTRL_MODE		0x0100
2832a437dbSMikhail Rudenko #define OV4689_MODE_SW_STANDBY		0x0
2932a437dbSMikhail Rudenko #define OV4689_MODE_STREAMING		BIT(0)
3032a437dbSMikhail Rudenko 
3132a437dbSMikhail Rudenko #define OV4689_REG_EXPOSURE		0x3500
3232a437dbSMikhail Rudenko #define OV4689_EXPOSURE_MIN		4
3332a437dbSMikhail Rudenko #define OV4689_EXPOSURE_STEP		1
3432a437dbSMikhail Rudenko #define OV4689_VTS_MAX			0x7fff
3532a437dbSMikhail Rudenko 
3632a437dbSMikhail Rudenko #define OV4689_REG_GAIN_H		0x3508
3732a437dbSMikhail Rudenko #define OV4689_REG_GAIN_L		0x3509
3832a437dbSMikhail Rudenko #define OV4689_GAIN_H_MASK		0x07
3932a437dbSMikhail Rudenko #define OV4689_GAIN_H_SHIFT		8
4032a437dbSMikhail Rudenko #define OV4689_GAIN_L_MASK		0xff
4132a437dbSMikhail Rudenko #define OV4689_GAIN_STEP		1
4232a437dbSMikhail Rudenko #define OV4689_GAIN_DEFAULT		0x80
4332a437dbSMikhail Rudenko 
4432a437dbSMikhail Rudenko #define OV4689_REG_TEST_PATTERN		0x5040
4532a437dbSMikhail Rudenko #define OV4689_TEST_PATTERN_ENABLE	0x80
4632a437dbSMikhail Rudenko #define OV4689_TEST_PATTERN_DISABLE	0x0
4732a437dbSMikhail Rudenko 
4832a437dbSMikhail Rudenko #define OV4689_REG_VTS			0x380e
4932a437dbSMikhail Rudenko 
5032a437dbSMikhail Rudenko #define REG_NULL			0xFFFF
5132a437dbSMikhail Rudenko 
5232a437dbSMikhail Rudenko #define OV4689_REG_VALUE_08BIT		1
5332a437dbSMikhail Rudenko #define OV4689_REG_VALUE_16BIT		2
5432a437dbSMikhail Rudenko #define OV4689_REG_VALUE_24BIT		3
5532a437dbSMikhail Rudenko 
5632a437dbSMikhail Rudenko #define OV4689_LANES			4
5732a437dbSMikhail Rudenko 
5832a437dbSMikhail Rudenko static const char *const ov4689_supply_names[] = {
5932a437dbSMikhail Rudenko 	"avdd", /* Analog power */
6032a437dbSMikhail Rudenko 	"dovdd", /* Digital I/O power */
6132a437dbSMikhail Rudenko 	"dvdd", /* Digital core power */
6232a437dbSMikhail Rudenko };
6332a437dbSMikhail Rudenko 
6432a437dbSMikhail Rudenko struct regval {
6532a437dbSMikhail Rudenko 	u16 addr;
6632a437dbSMikhail Rudenko 	u8 val;
6732a437dbSMikhail Rudenko };
6832a437dbSMikhail Rudenko 
6932a437dbSMikhail Rudenko enum ov4689_mode_id {
7032a437dbSMikhail Rudenko 	OV4689_MODE_2688_1520 = 0,
7132a437dbSMikhail Rudenko 	OV4689_NUM_MODES,
7232a437dbSMikhail Rudenko };
7332a437dbSMikhail Rudenko 
7432a437dbSMikhail Rudenko struct ov4689_mode {
7532a437dbSMikhail Rudenko 	enum ov4689_mode_id id;
7632a437dbSMikhail Rudenko 	u32 width;
7732a437dbSMikhail Rudenko 	u32 height;
7832a437dbSMikhail Rudenko 	u32 max_fps;
7932a437dbSMikhail Rudenko 	u32 hts_def;
8032a437dbSMikhail Rudenko 	u32 vts_def;
8132a437dbSMikhail Rudenko 	u32 exp_def;
8232a437dbSMikhail Rudenko 	u32 pixel_rate;
8332a437dbSMikhail Rudenko 	u32 sensor_width;
8432a437dbSMikhail Rudenko 	u32 sensor_height;
8532a437dbSMikhail Rudenko 	u32 crop_top;
8632a437dbSMikhail Rudenko 	u32 crop_left;
8732a437dbSMikhail Rudenko 	const struct regval *reg_list;
8832a437dbSMikhail Rudenko };
8932a437dbSMikhail Rudenko 
9032a437dbSMikhail Rudenko struct ov4689 {
9132a437dbSMikhail Rudenko 	struct i2c_client *client;
9232a437dbSMikhail Rudenko 	struct clk *xvclk;
9332a437dbSMikhail Rudenko 	struct gpio_desc *reset_gpio;
9432a437dbSMikhail Rudenko 	struct gpio_desc *pwdn_gpio;
9532a437dbSMikhail Rudenko 	struct regulator_bulk_data supplies[ARRAY_SIZE(ov4689_supply_names)];
9632a437dbSMikhail Rudenko 
9732a437dbSMikhail Rudenko 	struct v4l2_subdev subdev;
9832a437dbSMikhail Rudenko 	struct media_pad pad;
9932a437dbSMikhail Rudenko 
10032a437dbSMikhail Rudenko 	u32 clock_rate;
10132a437dbSMikhail Rudenko 
10232a437dbSMikhail Rudenko 	struct mutex mutex; /* lock to protect streaming, ctrls and cur_mode */
10332a437dbSMikhail Rudenko 	bool streaming;
10432a437dbSMikhail Rudenko 	struct v4l2_ctrl_handler ctrl_handler;
10532a437dbSMikhail Rudenko 	struct v4l2_ctrl *exposure;
10632a437dbSMikhail Rudenko 
10732a437dbSMikhail Rudenko 	const struct ov4689_mode *cur_mode;
10832a437dbSMikhail Rudenko };
10932a437dbSMikhail Rudenko 
11032a437dbSMikhail Rudenko #define to_ov4689(sd) container_of(sd, struct ov4689, subdev)
11132a437dbSMikhail Rudenko 
11232a437dbSMikhail Rudenko struct ov4689_gain_range {
11332a437dbSMikhail Rudenko 	u32 logical_min;
11432a437dbSMikhail Rudenko 	u32 logical_max;
11532a437dbSMikhail Rudenko 	u32 offset;
11632a437dbSMikhail Rudenko 	u32 divider;
11732a437dbSMikhail Rudenko 	u32 physical_min;
11832a437dbSMikhail Rudenko 	u32 physical_max;
11932a437dbSMikhail Rudenko };
12032a437dbSMikhail Rudenko 
12132a437dbSMikhail Rudenko /*
12232a437dbSMikhail Rudenko  * Xclk 24Mhz
12332a437dbSMikhail Rudenko  * max_framerate 30fps
12432a437dbSMikhail Rudenko  * mipi_datarate per lane 1008Mbps
12532a437dbSMikhail Rudenko  */
12632a437dbSMikhail Rudenko static const struct regval ov4689_2688x1520_regs[] = {
12732a437dbSMikhail Rudenko 	{0x0103, 0x01}, {0x3638, 0x00}, {0x0300, 0x00},
12832a437dbSMikhail Rudenko 	{0x0302, 0x2a}, {0x0303, 0x00}, {0x0304, 0x03},
12932a437dbSMikhail Rudenko 	{0x030b, 0x00}, {0x030d, 0x1e}, {0x030e, 0x04},
13032a437dbSMikhail Rudenko 	{0x030f, 0x01}, {0x0312, 0x01}, {0x031e, 0x00},
13132a437dbSMikhail Rudenko 	{0x3000, 0x20}, {0x3002, 0x00}, {0x3018, 0x72},
13232a437dbSMikhail Rudenko 	{0x3020, 0x93}, {0x3021, 0x03}, {0x3022, 0x01},
13332a437dbSMikhail Rudenko 	{0x3031, 0x0a}, {0x303f, 0x0c}, {0x3305, 0xf1},
13432a437dbSMikhail Rudenko 	{0x3307, 0x04}, {0x3309, 0x29}, {0x3500, 0x00},
13532a437dbSMikhail Rudenko 	{0x3501, 0x60}, {0x3502, 0x00}, {0x3503, 0x04},
13632a437dbSMikhail Rudenko 	{0x3504, 0x00}, {0x3505, 0x00}, {0x3506, 0x00},
13732a437dbSMikhail Rudenko 	{0x3507, 0x00}, {0x3508, 0x00}, {0x3509, 0x80},
13832a437dbSMikhail Rudenko 	{0x350a, 0x00}, {0x350b, 0x00}, {0x350c, 0x00},
13932a437dbSMikhail Rudenko 	{0x350d, 0x00}, {0x350e, 0x00}, {0x350f, 0x80},
14032a437dbSMikhail Rudenko 	{0x3510, 0x00}, {0x3511, 0x00}, {0x3512, 0x00},
14132a437dbSMikhail Rudenko 	{0x3513, 0x00}, {0x3514, 0x00}, {0x3515, 0x80},
14232a437dbSMikhail Rudenko 	{0x3516, 0x00}, {0x3517, 0x00}, {0x3518, 0x00},
14332a437dbSMikhail Rudenko 	{0x3519, 0x00}, {0x351a, 0x00}, {0x351b, 0x80},
14432a437dbSMikhail Rudenko 	{0x351c, 0x00}, {0x351d, 0x00}, {0x351e, 0x00},
14532a437dbSMikhail Rudenko 	{0x351f, 0x00}, {0x3520, 0x00}, {0x3521, 0x80},
14632a437dbSMikhail Rudenko 	{0x3522, 0x08}, {0x3524, 0x08}, {0x3526, 0x08},
14732a437dbSMikhail Rudenko 	{0x3528, 0x08}, {0x352a, 0x08}, {0x3602, 0x00},
14832a437dbSMikhail Rudenko 	{0x3603, 0x40}, {0x3604, 0x02}, {0x3605, 0x00},
14932a437dbSMikhail Rudenko 	{0x3606, 0x00}, {0x3607, 0x00}, {0x3609, 0x12},
15032a437dbSMikhail Rudenko 	{0x360a, 0x40}, {0x360c, 0x08}, {0x360f, 0xe5},
15132a437dbSMikhail Rudenko 	{0x3608, 0x8f}, {0x3611, 0x00}, {0x3613, 0xf7},
15232a437dbSMikhail Rudenko 	{0x3616, 0x58}, {0x3619, 0x99}, {0x361b, 0x60},
15332a437dbSMikhail Rudenko 	{0x361c, 0x7a}, {0x361e, 0x79}, {0x361f, 0x02},
15432a437dbSMikhail Rudenko 	{0x3632, 0x00}, {0x3633, 0x10}, {0x3634, 0x10},
15532a437dbSMikhail Rudenko 	{0x3635, 0x10}, {0x3636, 0x15}, {0x3646, 0x86},
15632a437dbSMikhail Rudenko 	{0x364a, 0x0b}, {0x3700, 0x17}, {0x3701, 0x22},
15732a437dbSMikhail Rudenko 	{0x3703, 0x10}, {0x370a, 0x37}, {0x3705, 0x00},
15832a437dbSMikhail Rudenko 	{0x3706, 0x63}, {0x3709, 0x3c}, {0x370b, 0x01},
15932a437dbSMikhail Rudenko 	{0x370c, 0x30}, {0x3710, 0x24}, {0x3711, 0x0c},
16032a437dbSMikhail Rudenko 	{0x3716, 0x00}, {0x3720, 0x28}, {0x3729, 0x7b},
16132a437dbSMikhail Rudenko 	{0x372a, 0x84}, {0x372b, 0xbd}, {0x372c, 0xbc},
16232a437dbSMikhail Rudenko 	{0x372e, 0x52}, {0x373c, 0x0e}, {0x373e, 0x33},
16332a437dbSMikhail Rudenko 	{0x3743, 0x10}, {0x3744, 0x88}, {0x3745, 0xc0},
16432a437dbSMikhail Rudenko 	{0x374a, 0x43}, {0x374c, 0x00}, {0x374e, 0x23},
16532a437dbSMikhail Rudenko 	{0x3751, 0x7b}, {0x3752, 0x84}, {0x3753, 0xbd},
16632a437dbSMikhail Rudenko 	{0x3754, 0xbc}, {0x3756, 0x52}, {0x375c, 0x00},
16732a437dbSMikhail Rudenko 	{0x3760, 0x00}, {0x3761, 0x00}, {0x3762, 0x00},
16832a437dbSMikhail Rudenko 	{0x3763, 0x00}, {0x3764, 0x00}, {0x3767, 0x04},
16932a437dbSMikhail Rudenko 	{0x3768, 0x04}, {0x3769, 0x08}, {0x376a, 0x08},
17032a437dbSMikhail Rudenko 	{0x376b, 0x20}, {0x376c, 0x00}, {0x376d, 0x00},
17132a437dbSMikhail Rudenko 	{0x376e, 0x00}, {0x3773, 0x00}, {0x3774, 0x51},
17232a437dbSMikhail Rudenko 	{0x3776, 0xbd}, {0x3777, 0xbd}, {0x3781, 0x18},
17332a437dbSMikhail Rudenko 	{0x3783, 0x25}, {0x3798, 0x1b}, {0x3800, 0x00},
17432a437dbSMikhail Rudenko 	{0x3801, 0x08}, {0x3802, 0x00}, {0x3803, 0x04},
17532a437dbSMikhail Rudenko 	{0x3804, 0x0a}, {0x3805, 0x97}, {0x3806, 0x05},
17632a437dbSMikhail Rudenko 	{0x3807, 0xfb}, {0x3808, 0x0a}, {0x3809, 0x80},
17732a437dbSMikhail Rudenko 	{0x380a, 0x05}, {0x380b, 0xf0}, {0x380c, 0x0a},
17832a437dbSMikhail Rudenko 	{0x380d, 0x0e}, {0x380e, 0x06}, {0x380f, 0x12},
17932a437dbSMikhail Rudenko 	{0x3810, 0x00}, {0x3811, 0x08}, {0x3812, 0x00},
18032a437dbSMikhail Rudenko 	{0x3813, 0x04}, {0x3814, 0x01}, {0x3815, 0x01},
18132a437dbSMikhail Rudenko 	{0x3819, 0x01}, {0x3820, 0x00}, {0x3821, 0x06},
18232a437dbSMikhail Rudenko 	{0x3829, 0x00}, {0x382a, 0x01}, {0x382b, 0x01},
18332a437dbSMikhail Rudenko 	{0x382d, 0x7f}, {0x3830, 0x04}, {0x3836, 0x01},
18432a437dbSMikhail Rudenko 	{0x3837, 0x00}, {0x3841, 0x02}, {0x3846, 0x08},
18532a437dbSMikhail Rudenko 	{0x3847, 0x07}, {0x3d85, 0x36}, {0x3d8c, 0x71},
18632a437dbSMikhail Rudenko 	{0x3d8d, 0xcb}, {0x3f0a, 0x00}, {0x4000, 0xf1},
18732a437dbSMikhail Rudenko 	{0x4001, 0x40}, {0x4002, 0x04}, {0x4003, 0x14},
18832a437dbSMikhail Rudenko 	{0x400e, 0x00}, {0x4011, 0x00}, {0x401a, 0x00},
18932a437dbSMikhail Rudenko 	{0x401b, 0x00}, {0x401c, 0x00}, {0x401d, 0x00},
19032a437dbSMikhail Rudenko 	{0x401f, 0x00}, {0x4020, 0x00}, {0x4021, 0x10},
19132a437dbSMikhail Rudenko 	{0x4022, 0x07}, {0x4023, 0xcf}, {0x4024, 0x09},
19232a437dbSMikhail Rudenko 	{0x4025, 0x60}, {0x4026, 0x09}, {0x4027, 0x6f},
19332a437dbSMikhail Rudenko 	{0x4028, 0x00}, {0x4029, 0x02}, {0x402a, 0x06},
19432a437dbSMikhail Rudenko 	{0x402b, 0x04}, {0x402c, 0x02}, {0x402d, 0x02},
19532a437dbSMikhail Rudenko 	{0x402e, 0x0e}, {0x402f, 0x04}, {0x4302, 0xff},
19632a437dbSMikhail Rudenko 	{0x4303, 0xff}, {0x4304, 0x00}, {0x4305, 0x00},
19732a437dbSMikhail Rudenko 	{0x4306, 0x00}, {0x4308, 0x02}, {0x4500, 0x6c},
19832a437dbSMikhail Rudenko 	{0x4501, 0xc4}, {0x4502, 0x40}, {0x4503, 0x01},
19932a437dbSMikhail Rudenko 	{0x4601, 0xa7}, {0x4800, 0x04}, {0x4813, 0x08},
20032a437dbSMikhail Rudenko 	{0x481f, 0x40}, {0x4829, 0x78}, {0x4837, 0x10},
20132a437dbSMikhail Rudenko 	{0x4b00, 0x2a}, {0x4b0d, 0x00}, {0x4d00, 0x04},
20232a437dbSMikhail Rudenko 	{0x4d01, 0x42}, {0x4d02, 0xd1}, {0x4d03, 0x93},
20332a437dbSMikhail Rudenko 	{0x4d04, 0xf5}, {0x4d05, 0xc1}, {0x5000, 0xf3},
20432a437dbSMikhail Rudenko 	{0x5001, 0x11}, {0x5004, 0x00}, {0x500a, 0x00},
20532a437dbSMikhail Rudenko 	{0x500b, 0x00}, {0x5032, 0x00}, {0x5040, 0x00},
20632a437dbSMikhail Rudenko 	{0x5050, 0x0c}, {0x5500, 0x00}, {0x5501, 0x10},
20732a437dbSMikhail Rudenko 	{0x5502, 0x01}, {0x5503, 0x0f}, {0x8000, 0x00},
20832a437dbSMikhail Rudenko 	{0x8001, 0x00}, {0x8002, 0x00}, {0x8003, 0x00},
20932a437dbSMikhail Rudenko 	{0x8004, 0x00}, {0x8005, 0x00}, {0x8006, 0x00},
21032a437dbSMikhail Rudenko 	{0x8007, 0x00}, {0x8008, 0x00}, {0x3638, 0x00},
21132a437dbSMikhail Rudenko 	{REG_NULL, 0x00},
21232a437dbSMikhail Rudenko };
21332a437dbSMikhail Rudenko 
21432a437dbSMikhail Rudenko static const struct ov4689_mode supported_modes[] = {
21532a437dbSMikhail Rudenko 	{
21632a437dbSMikhail Rudenko 		.id = OV4689_MODE_2688_1520,
21732a437dbSMikhail Rudenko 		.width = 2688,
21832a437dbSMikhail Rudenko 		.height = 1520,
21932a437dbSMikhail Rudenko 		.sensor_width = 2720,
22032a437dbSMikhail Rudenko 		.sensor_height = 1536,
22132a437dbSMikhail Rudenko 		.crop_top = 8,
22232a437dbSMikhail Rudenko 		.crop_left = 16,
22332a437dbSMikhail Rudenko 		.max_fps = 30,
22432a437dbSMikhail Rudenko 		.exp_def = 1536,
22532a437dbSMikhail Rudenko 		.hts_def = 4 * 2574,
22632a437dbSMikhail Rudenko 		.vts_def = 1554,
22732a437dbSMikhail Rudenko 		.pixel_rate = 480000000,
22832a437dbSMikhail Rudenko 		.reg_list = ov4689_2688x1520_regs,
22932a437dbSMikhail Rudenko 	},
23032a437dbSMikhail Rudenko };
23132a437dbSMikhail Rudenko 
23232a437dbSMikhail Rudenko static const u64 link_freq_menu_items[] = { 504000000 };
23332a437dbSMikhail Rudenko 
23432a437dbSMikhail Rudenko static const char *const ov4689_test_pattern_menu[] = {
23532a437dbSMikhail Rudenko 	"Disabled",
23632a437dbSMikhail Rudenko 	"Vertical Color Bar Type 1",
23732a437dbSMikhail Rudenko 	"Vertical Color Bar Type 2",
23832a437dbSMikhail Rudenko 	"Vertical Color Bar Type 3",
23932a437dbSMikhail Rudenko 	"Vertical Color Bar Type 4"
24032a437dbSMikhail Rudenko };
24132a437dbSMikhail Rudenko 
24232a437dbSMikhail Rudenko /*
24332a437dbSMikhail Rudenko  * These coefficients are based on those used in Rockchip's camera
24432a437dbSMikhail Rudenko  * engine, with minor tweaks for continuity.
24532a437dbSMikhail Rudenko  */
24632a437dbSMikhail Rudenko static const struct ov4689_gain_range ov4689_gain_ranges[] = {
24732a437dbSMikhail Rudenko 	{
24832a437dbSMikhail Rudenko 		.logical_min = 0,
24932a437dbSMikhail Rudenko 		.logical_max = 255,
25032a437dbSMikhail Rudenko 		.offset = 0,
25132a437dbSMikhail Rudenko 		.divider = 1,
25232a437dbSMikhail Rudenko 		.physical_min = 0,
25332a437dbSMikhail Rudenko 		.physical_max = 255,
25432a437dbSMikhail Rudenko 	},
25532a437dbSMikhail Rudenko 	{
25632a437dbSMikhail Rudenko 		.logical_min = 256,
25732a437dbSMikhail Rudenko 		.logical_max = 511,
25832a437dbSMikhail Rudenko 		.offset = 252,
25932a437dbSMikhail Rudenko 		.divider = 2,
26032a437dbSMikhail Rudenko 		.physical_min = 376,
26132a437dbSMikhail Rudenko 		.physical_max = 504,
26232a437dbSMikhail Rudenko 	},
26332a437dbSMikhail Rudenko 	{
26432a437dbSMikhail Rudenko 		.logical_min = 512,
26532a437dbSMikhail Rudenko 		.logical_max = 1023,
26632a437dbSMikhail Rudenko 		.offset = 758,
26732a437dbSMikhail Rudenko 		.divider = 4,
26832a437dbSMikhail Rudenko 		.physical_min = 884,
26932a437dbSMikhail Rudenko 		.physical_max = 1012,
27032a437dbSMikhail Rudenko 	},
27132a437dbSMikhail Rudenko 	{
27232a437dbSMikhail Rudenko 		.logical_min = 1024,
27332a437dbSMikhail Rudenko 		.logical_max = 2047,
27432a437dbSMikhail Rudenko 		.offset = 1788,
27532a437dbSMikhail Rudenko 		.divider = 8,
27632a437dbSMikhail Rudenko 		.physical_min = 1912,
27732a437dbSMikhail Rudenko 		.physical_max = 2047,
27832a437dbSMikhail Rudenko 	},
27932a437dbSMikhail Rudenko };
28032a437dbSMikhail Rudenko 
28132a437dbSMikhail Rudenko /* Write registers up to 4 at a time */
ov4689_write_reg(struct i2c_client * client,u16 reg,u32 len,u32 val)28232a437dbSMikhail Rudenko static int ov4689_write_reg(struct i2c_client *client, u16 reg, u32 len,
28332a437dbSMikhail Rudenko 			    u32 val)
28432a437dbSMikhail Rudenko {
28532a437dbSMikhail Rudenko 	u32 buf_i, val_i;
28632a437dbSMikhail Rudenko 	__be32 val_be;
28732a437dbSMikhail Rudenko 	u8 *val_p;
28832a437dbSMikhail Rudenko 	u8 buf[6];
28932a437dbSMikhail Rudenko 
29032a437dbSMikhail Rudenko 	if (len > 4)
29132a437dbSMikhail Rudenko 		return -EINVAL;
29232a437dbSMikhail Rudenko 
29332a437dbSMikhail Rudenko 	buf[0] = reg >> 8;
29432a437dbSMikhail Rudenko 	buf[1] = reg & 0xff;
29532a437dbSMikhail Rudenko 
29632a437dbSMikhail Rudenko 	val_be = cpu_to_be32(val);
29732a437dbSMikhail Rudenko 	val_p = (u8 *)&val_be;
29832a437dbSMikhail Rudenko 	buf_i = 2;
29932a437dbSMikhail Rudenko 	val_i = 4 - len;
30032a437dbSMikhail Rudenko 
30132a437dbSMikhail Rudenko 	while (val_i < 4)
30232a437dbSMikhail Rudenko 		buf[buf_i++] = val_p[val_i++];
30332a437dbSMikhail Rudenko 
30432a437dbSMikhail Rudenko 	if (i2c_master_send(client, buf, len + 2) != len + 2)
30532a437dbSMikhail Rudenko 		return -EIO;
30632a437dbSMikhail Rudenko 
30732a437dbSMikhail Rudenko 	return 0;
30832a437dbSMikhail Rudenko }
30932a437dbSMikhail Rudenko 
ov4689_write_array(struct i2c_client * client,const struct regval * regs)31032a437dbSMikhail Rudenko static int ov4689_write_array(struct i2c_client *client,
31132a437dbSMikhail Rudenko 			      const struct regval *regs)
31232a437dbSMikhail Rudenko {
31332a437dbSMikhail Rudenko 	int ret = 0;
31432a437dbSMikhail Rudenko 	u32 i;
31532a437dbSMikhail Rudenko 
31632a437dbSMikhail Rudenko 	for (i = 0; ret == 0 && regs[i].addr != REG_NULL; i++)
31732a437dbSMikhail Rudenko 		ret = ov4689_write_reg(client, regs[i].addr,
31832a437dbSMikhail Rudenko 				       OV4689_REG_VALUE_08BIT, regs[i].val);
31932a437dbSMikhail Rudenko 
32032a437dbSMikhail Rudenko 	return ret;
32132a437dbSMikhail Rudenko }
32232a437dbSMikhail Rudenko 
32332a437dbSMikhail Rudenko /* Read registers up to 4 at a time */
ov4689_read_reg(struct i2c_client * client,u16 reg,unsigned int len,u32 * val)32432a437dbSMikhail Rudenko static int ov4689_read_reg(struct i2c_client *client, u16 reg, unsigned int len,
32532a437dbSMikhail Rudenko 			   u32 *val)
32632a437dbSMikhail Rudenko {
32732a437dbSMikhail Rudenko 	__be16 reg_addr_be = cpu_to_be16(reg);
32832a437dbSMikhail Rudenko 	struct i2c_msg msgs[2];
32932a437dbSMikhail Rudenko 	__be32 data_be = 0;
33032a437dbSMikhail Rudenko 	u8 *data_be_p;
33132a437dbSMikhail Rudenko 	int ret;
33232a437dbSMikhail Rudenko 
33332a437dbSMikhail Rudenko 	if (len > 4 || !len)
33432a437dbSMikhail Rudenko 		return -EINVAL;
33532a437dbSMikhail Rudenko 
33632a437dbSMikhail Rudenko 	data_be_p = (u8 *)&data_be;
33732a437dbSMikhail Rudenko 	/* Write register address */
33832a437dbSMikhail Rudenko 	msgs[0].addr = client->addr;
33932a437dbSMikhail Rudenko 	msgs[0].flags = 0;
34032a437dbSMikhail Rudenko 	msgs[0].len = 2;
34132a437dbSMikhail Rudenko 	msgs[0].buf = (u8 *)&reg_addr_be;
34232a437dbSMikhail Rudenko 
34332a437dbSMikhail Rudenko 	/* Read data from register */
34432a437dbSMikhail Rudenko 	msgs[1].addr = client->addr;
34532a437dbSMikhail Rudenko 	msgs[1].flags = I2C_M_RD;
34632a437dbSMikhail Rudenko 	msgs[1].len = len;
34732a437dbSMikhail Rudenko 	msgs[1].buf = &data_be_p[4 - len];
34832a437dbSMikhail Rudenko 
34932a437dbSMikhail Rudenko 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
35032a437dbSMikhail Rudenko 	if (ret != ARRAY_SIZE(msgs))
35132a437dbSMikhail Rudenko 		return -EIO;
35232a437dbSMikhail Rudenko 
35332a437dbSMikhail Rudenko 	*val = be32_to_cpu(data_be);
35432a437dbSMikhail Rudenko 
35532a437dbSMikhail Rudenko 	return 0;
35632a437dbSMikhail Rudenko }
35732a437dbSMikhail Rudenko 
ov4689_fill_fmt(const struct ov4689_mode * mode,struct v4l2_mbus_framefmt * fmt)35832a437dbSMikhail Rudenko static void ov4689_fill_fmt(const struct ov4689_mode *mode,
35932a437dbSMikhail Rudenko 			    struct v4l2_mbus_framefmt *fmt)
36032a437dbSMikhail Rudenko {
36132a437dbSMikhail Rudenko 	fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
36232a437dbSMikhail Rudenko 	fmt->width = mode->width;
36332a437dbSMikhail Rudenko 	fmt->height = mode->height;
36432a437dbSMikhail Rudenko 	fmt->field = V4L2_FIELD_NONE;
36532a437dbSMikhail Rudenko }
36632a437dbSMikhail Rudenko 
ov4689_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)36732a437dbSMikhail Rudenko static int ov4689_set_fmt(struct v4l2_subdev *sd,
36832a437dbSMikhail Rudenko 			  struct v4l2_subdev_state *sd_state,
36932a437dbSMikhail Rudenko 			  struct v4l2_subdev_format *fmt)
37032a437dbSMikhail Rudenko {
37132a437dbSMikhail Rudenko 	struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
37232a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
37332a437dbSMikhail Rudenko 
37432a437dbSMikhail Rudenko 	/* only one mode supported for now */
37532a437dbSMikhail Rudenko 	ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt);
37632a437dbSMikhail Rudenko 
37732a437dbSMikhail Rudenko 	return 0;
37832a437dbSMikhail Rudenko }
37932a437dbSMikhail Rudenko 
ov4689_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)38032a437dbSMikhail Rudenko static int ov4689_get_fmt(struct v4l2_subdev *sd,
38132a437dbSMikhail Rudenko 			  struct v4l2_subdev_state *sd_state,
38232a437dbSMikhail Rudenko 			  struct v4l2_subdev_format *fmt)
38332a437dbSMikhail Rudenko {
38432a437dbSMikhail Rudenko 	struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format;
38532a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
38632a437dbSMikhail Rudenko 
38732a437dbSMikhail Rudenko 	/* only one mode supported for now */
38832a437dbSMikhail Rudenko 	ov4689_fill_fmt(ov4689->cur_mode, mbus_fmt);
38932a437dbSMikhail Rudenko 
39032a437dbSMikhail Rudenko 	return 0;
39132a437dbSMikhail Rudenko }
39232a437dbSMikhail Rudenko 
ov4689_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)39332a437dbSMikhail Rudenko static int ov4689_enum_mbus_code(struct v4l2_subdev *sd,
39432a437dbSMikhail Rudenko 				 struct v4l2_subdev_state *sd_state,
39532a437dbSMikhail Rudenko 				 struct v4l2_subdev_mbus_code_enum *code)
39632a437dbSMikhail Rudenko {
39732a437dbSMikhail Rudenko 	if (code->index != 0)
39832a437dbSMikhail Rudenko 		return -EINVAL;
39932a437dbSMikhail Rudenko 	code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
40032a437dbSMikhail Rudenko 
40132a437dbSMikhail Rudenko 	return 0;
40232a437dbSMikhail Rudenko }
40332a437dbSMikhail Rudenko 
ov4689_enum_frame_sizes(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)40432a437dbSMikhail Rudenko static int ov4689_enum_frame_sizes(struct v4l2_subdev *sd,
40532a437dbSMikhail Rudenko 				   struct v4l2_subdev_state *sd_state,
40632a437dbSMikhail Rudenko 				   struct v4l2_subdev_frame_size_enum *fse)
40732a437dbSMikhail Rudenko {
40832a437dbSMikhail Rudenko 	if (fse->index >= ARRAY_SIZE(supported_modes))
40932a437dbSMikhail Rudenko 		return -EINVAL;
41032a437dbSMikhail Rudenko 
41132a437dbSMikhail Rudenko 	if (fse->code != MEDIA_BUS_FMT_SBGGR10_1X10)
41232a437dbSMikhail Rudenko 		return -EINVAL;
41332a437dbSMikhail Rudenko 
41432a437dbSMikhail Rudenko 	fse->min_width = supported_modes[fse->index].width;
41532a437dbSMikhail Rudenko 	fse->max_width = supported_modes[fse->index].width;
41632a437dbSMikhail Rudenko 	fse->max_height = supported_modes[fse->index].height;
41732a437dbSMikhail Rudenko 	fse->min_height = supported_modes[fse->index].height;
41832a437dbSMikhail Rudenko 
41932a437dbSMikhail Rudenko 	return 0;
42032a437dbSMikhail Rudenko }
42132a437dbSMikhail Rudenko 
ov4689_enable_test_pattern(struct ov4689 * ov4689,u32 pattern)42232a437dbSMikhail Rudenko static int ov4689_enable_test_pattern(struct ov4689 *ov4689, u32 pattern)
42332a437dbSMikhail Rudenko {
42432a437dbSMikhail Rudenko 	u32 val;
42532a437dbSMikhail Rudenko 
42632a437dbSMikhail Rudenko 	if (pattern)
42732a437dbSMikhail Rudenko 		val = (pattern - 1) | OV4689_TEST_PATTERN_ENABLE;
42832a437dbSMikhail Rudenko 	else
42932a437dbSMikhail Rudenko 		val = OV4689_TEST_PATTERN_DISABLE;
43032a437dbSMikhail Rudenko 
43132a437dbSMikhail Rudenko 	return ov4689_write_reg(ov4689->client, OV4689_REG_TEST_PATTERN,
43232a437dbSMikhail Rudenko 				OV4689_REG_VALUE_08BIT, val);
43332a437dbSMikhail Rudenko }
43432a437dbSMikhail Rudenko 
ov4689_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_state * state,struct v4l2_subdev_selection * sel)43532a437dbSMikhail Rudenko static int ov4689_get_selection(struct v4l2_subdev *sd,
43632a437dbSMikhail Rudenko 				struct v4l2_subdev_state *state,
43732a437dbSMikhail Rudenko 				struct v4l2_subdev_selection *sel)
43832a437dbSMikhail Rudenko {
43932a437dbSMikhail Rudenko 	const struct ov4689_mode *mode = to_ov4689(sd)->cur_mode;
44032a437dbSMikhail Rudenko 
44132a437dbSMikhail Rudenko 	if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
44232a437dbSMikhail Rudenko 		return -EINVAL;
44332a437dbSMikhail Rudenko 
44432a437dbSMikhail Rudenko 	switch (sel->target) {
44532a437dbSMikhail Rudenko 	case V4L2_SEL_TGT_CROP_BOUNDS:
44632a437dbSMikhail Rudenko 		sel->r.top = 0;
44732a437dbSMikhail Rudenko 		sel->r.left = 0;
44832a437dbSMikhail Rudenko 		sel->r.width = mode->sensor_width;
44932a437dbSMikhail Rudenko 		sel->r.height = mode->sensor_height;
45032a437dbSMikhail Rudenko 		return 0;
45132a437dbSMikhail Rudenko 	case V4L2_SEL_TGT_CROP:
45232a437dbSMikhail Rudenko 	case V4L2_SEL_TGT_CROP_DEFAULT:
45332a437dbSMikhail Rudenko 		sel->r.top = mode->crop_top;
45432a437dbSMikhail Rudenko 		sel->r.left = mode->crop_left;
45532a437dbSMikhail Rudenko 		sel->r.width = mode->width;
45632a437dbSMikhail Rudenko 		sel->r.height = mode->height;
45732a437dbSMikhail Rudenko 		return 0;
45832a437dbSMikhail Rudenko 	}
45932a437dbSMikhail Rudenko 
46032a437dbSMikhail Rudenko 	return -EINVAL;
46132a437dbSMikhail Rudenko }
46232a437dbSMikhail Rudenko 
ov4689_s_stream(struct v4l2_subdev * sd,int on)46332a437dbSMikhail Rudenko static int ov4689_s_stream(struct v4l2_subdev *sd, int on)
46432a437dbSMikhail Rudenko {
46532a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
46632a437dbSMikhail Rudenko 	struct i2c_client *client = ov4689->client;
46732a437dbSMikhail Rudenko 	int ret = 0;
46832a437dbSMikhail Rudenko 
46932a437dbSMikhail Rudenko 	mutex_lock(&ov4689->mutex);
47032a437dbSMikhail Rudenko 
47132a437dbSMikhail Rudenko 	on = !!on;
47232a437dbSMikhail Rudenko 	if (on == ov4689->streaming)
47332a437dbSMikhail Rudenko 		goto unlock_and_return;
47432a437dbSMikhail Rudenko 
47532a437dbSMikhail Rudenko 	if (on) {
47632a437dbSMikhail Rudenko 		ret = pm_runtime_resume_and_get(&client->dev);
47732a437dbSMikhail Rudenko 		if (ret < 0)
47832a437dbSMikhail Rudenko 			goto unlock_and_return;
47932a437dbSMikhail Rudenko 
48032a437dbSMikhail Rudenko 		ret = ov4689_write_array(ov4689->client,
48132a437dbSMikhail Rudenko 					 ov4689->cur_mode->reg_list);
48232a437dbSMikhail Rudenko 		if (ret) {
48332a437dbSMikhail Rudenko 			pm_runtime_put(&client->dev);
48432a437dbSMikhail Rudenko 			goto unlock_and_return;
48532a437dbSMikhail Rudenko 		}
48632a437dbSMikhail Rudenko 
48732a437dbSMikhail Rudenko 		ret = __v4l2_ctrl_handler_setup(&ov4689->ctrl_handler);
48832a437dbSMikhail Rudenko 		if (ret) {
48932a437dbSMikhail Rudenko 			pm_runtime_put(&client->dev);
49032a437dbSMikhail Rudenko 			goto unlock_and_return;
49132a437dbSMikhail Rudenko 		}
49232a437dbSMikhail Rudenko 
49332a437dbSMikhail Rudenko 		ret = ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,
49432a437dbSMikhail Rudenko 				       OV4689_REG_VALUE_08BIT,
49532a437dbSMikhail Rudenko 				       OV4689_MODE_STREAMING);
49632a437dbSMikhail Rudenko 		if (ret) {
49732a437dbSMikhail Rudenko 			pm_runtime_put(&client->dev);
49832a437dbSMikhail Rudenko 			goto unlock_and_return;
49932a437dbSMikhail Rudenko 		}
50032a437dbSMikhail Rudenko 	} else {
50132a437dbSMikhail Rudenko 		ov4689_write_reg(ov4689->client, OV4689_REG_CTRL_MODE,
50232a437dbSMikhail Rudenko 				 OV4689_REG_VALUE_08BIT,
50332a437dbSMikhail Rudenko 				 OV4689_MODE_SW_STANDBY);
50432a437dbSMikhail Rudenko 		pm_runtime_put(&client->dev);
50532a437dbSMikhail Rudenko 	}
50632a437dbSMikhail Rudenko 
50732a437dbSMikhail Rudenko 	ov4689->streaming = on;
50832a437dbSMikhail Rudenko 
50932a437dbSMikhail Rudenko unlock_and_return:
51032a437dbSMikhail Rudenko 	mutex_unlock(&ov4689->mutex);
51132a437dbSMikhail Rudenko 
51232a437dbSMikhail Rudenko 	return ret;
51332a437dbSMikhail Rudenko }
51432a437dbSMikhail Rudenko 
51532a437dbSMikhail Rudenko /* Calculate the delay in us by clock rate and clock cycles */
ov4689_cal_delay(struct ov4689 * ov4689,u32 cycles)51632a437dbSMikhail Rudenko static inline u32 ov4689_cal_delay(struct ov4689 *ov4689, u32 cycles)
51732a437dbSMikhail Rudenko {
51832a437dbSMikhail Rudenko 	return DIV_ROUND_UP(cycles * 1000,
51932a437dbSMikhail Rudenko 			    DIV_ROUND_UP(ov4689->clock_rate, 1000));
52032a437dbSMikhail Rudenko }
52132a437dbSMikhail Rudenko 
ov4689_power_on(struct device * dev)52232a437dbSMikhail Rudenko static int __maybe_unused ov4689_power_on(struct device *dev)
52332a437dbSMikhail Rudenko {
52432a437dbSMikhail Rudenko 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
52532a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
52632a437dbSMikhail Rudenko 	u32 delay_us;
52732a437dbSMikhail Rudenko 	int ret;
52832a437dbSMikhail Rudenko 
52932a437dbSMikhail Rudenko 	ret = clk_prepare_enable(ov4689->xvclk);
53032a437dbSMikhail Rudenko 	if (ret < 0) {
53132a437dbSMikhail Rudenko 		dev_err(dev, "Failed to enable xvclk\n");
53232a437dbSMikhail Rudenko 		return ret;
53332a437dbSMikhail Rudenko 	}
53432a437dbSMikhail Rudenko 
53532a437dbSMikhail Rudenko 	gpiod_set_value_cansleep(ov4689->reset_gpio, 1);
53632a437dbSMikhail Rudenko 
53732a437dbSMikhail Rudenko 	ret = regulator_bulk_enable(ARRAY_SIZE(ov4689_supply_names),
53832a437dbSMikhail Rudenko 				    ov4689->supplies);
53932a437dbSMikhail Rudenko 	if (ret < 0) {
54032a437dbSMikhail Rudenko 		dev_err(dev, "Failed to enable regulators\n");
54132a437dbSMikhail Rudenko 		goto disable_clk;
54232a437dbSMikhail Rudenko 	}
54332a437dbSMikhail Rudenko 
54432a437dbSMikhail Rudenko 	gpiod_set_value_cansleep(ov4689->reset_gpio, 0);
54532a437dbSMikhail Rudenko 	usleep_range(500, 1000);
54632a437dbSMikhail Rudenko 	gpiod_set_value_cansleep(ov4689->pwdn_gpio, 0);
54732a437dbSMikhail Rudenko 
54832a437dbSMikhail Rudenko 	/* 8192 cycles prior to first SCCB transaction */
54932a437dbSMikhail Rudenko 	delay_us = ov4689_cal_delay(ov4689, 8192);
55032a437dbSMikhail Rudenko 	usleep_range(delay_us, delay_us * 2);
55132a437dbSMikhail Rudenko 
55232a437dbSMikhail Rudenko 	return 0;
55332a437dbSMikhail Rudenko 
55432a437dbSMikhail Rudenko disable_clk:
55532a437dbSMikhail Rudenko 	clk_disable_unprepare(ov4689->xvclk);
55632a437dbSMikhail Rudenko 
55732a437dbSMikhail Rudenko 	return ret;
55832a437dbSMikhail Rudenko }
55932a437dbSMikhail Rudenko 
ov4689_power_off(struct device * dev)56032a437dbSMikhail Rudenko static int __maybe_unused ov4689_power_off(struct device *dev)
56132a437dbSMikhail Rudenko {
56232a437dbSMikhail Rudenko 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
56332a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
56432a437dbSMikhail Rudenko 
56532a437dbSMikhail Rudenko 	gpiod_set_value_cansleep(ov4689->pwdn_gpio, 1);
56632a437dbSMikhail Rudenko 	clk_disable_unprepare(ov4689->xvclk);
56732a437dbSMikhail Rudenko 	gpiod_set_value_cansleep(ov4689->reset_gpio, 1);
56832a437dbSMikhail Rudenko 	regulator_bulk_disable(ARRAY_SIZE(ov4689_supply_names),
56932a437dbSMikhail Rudenko 			       ov4689->supplies);
57032a437dbSMikhail Rudenko 	return 0;
57132a437dbSMikhail Rudenko }
57232a437dbSMikhail Rudenko 
ov4689_open(struct v4l2_subdev * sd,struct v4l2_subdev_fh * fh)57332a437dbSMikhail Rudenko static int ov4689_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
57432a437dbSMikhail Rudenko {
57532a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
57632a437dbSMikhail Rudenko 	struct v4l2_mbus_framefmt *try_fmt;
57732a437dbSMikhail Rudenko 
57832a437dbSMikhail Rudenko 	mutex_lock(&ov4689->mutex);
57932a437dbSMikhail Rudenko 
58032a437dbSMikhail Rudenko 	try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0);
58132a437dbSMikhail Rudenko 	/* Initialize try_fmt */
58232a437dbSMikhail Rudenko 	ov4689_fill_fmt(&supported_modes[OV4689_MODE_2688_1520], try_fmt);
58332a437dbSMikhail Rudenko 
58432a437dbSMikhail Rudenko 	mutex_unlock(&ov4689->mutex);
58532a437dbSMikhail Rudenko 
58632a437dbSMikhail Rudenko 	return 0;
58732a437dbSMikhail Rudenko }
58832a437dbSMikhail Rudenko 
58932a437dbSMikhail Rudenko static const struct dev_pm_ops ov4689_pm_ops = {
59032a437dbSMikhail Rudenko 	SET_RUNTIME_PM_OPS(ov4689_power_off, ov4689_power_on, NULL)
59132a437dbSMikhail Rudenko };
59232a437dbSMikhail Rudenko 
59332a437dbSMikhail Rudenko static const struct v4l2_subdev_internal_ops ov4689_internal_ops = {
59432a437dbSMikhail Rudenko 	.open = ov4689_open,
59532a437dbSMikhail Rudenko };
59632a437dbSMikhail Rudenko 
59732a437dbSMikhail Rudenko static const struct v4l2_subdev_video_ops ov4689_video_ops = {
59832a437dbSMikhail Rudenko 	.s_stream = ov4689_s_stream,
59932a437dbSMikhail Rudenko };
60032a437dbSMikhail Rudenko 
60132a437dbSMikhail Rudenko static const struct v4l2_subdev_pad_ops ov4689_pad_ops = {
60232a437dbSMikhail Rudenko 	.enum_mbus_code = ov4689_enum_mbus_code,
60332a437dbSMikhail Rudenko 	.enum_frame_size = ov4689_enum_frame_sizes,
60432a437dbSMikhail Rudenko 	.get_fmt = ov4689_get_fmt,
60532a437dbSMikhail Rudenko 	.set_fmt = ov4689_set_fmt,
60632a437dbSMikhail Rudenko 	.get_selection = ov4689_get_selection,
60732a437dbSMikhail Rudenko };
60832a437dbSMikhail Rudenko 
60932a437dbSMikhail Rudenko static const struct v4l2_subdev_ops ov4689_subdev_ops = {
61032a437dbSMikhail Rudenko 	.video = &ov4689_video_ops,
61132a437dbSMikhail Rudenko 	.pad = &ov4689_pad_ops,
61232a437dbSMikhail Rudenko };
61332a437dbSMikhail Rudenko 
61432a437dbSMikhail Rudenko /*
61532a437dbSMikhail Rudenko  * Map userspace (logical) gain to sensor (physical) gain using
61632a437dbSMikhail Rudenko  * ov4689_gain_ranges table.
61732a437dbSMikhail Rudenko  */
ov4689_map_gain(struct ov4689 * ov4689,int logical_gain,int * result)61832a437dbSMikhail Rudenko static int ov4689_map_gain(struct ov4689 *ov4689, int logical_gain, int *result)
61932a437dbSMikhail Rudenko {
62032a437dbSMikhail Rudenko 	const struct device *dev = &ov4689->client->dev;
62132a437dbSMikhail Rudenko 	const struct ov4689_gain_range *range;
62232a437dbSMikhail Rudenko 	unsigned int n;
62332a437dbSMikhail Rudenko 
62432a437dbSMikhail Rudenko 	for (n = 0; n < ARRAY_SIZE(ov4689_gain_ranges); n++) {
62532a437dbSMikhail Rudenko 		if (logical_gain >= ov4689_gain_ranges[n].logical_min &&
6267336c54aSMikhail Rudenko 		    logical_gain <= ov4689_gain_ranges[n].logical_max)
62732a437dbSMikhail Rudenko 			break;
62832a437dbSMikhail Rudenko 	}
62932a437dbSMikhail Rudenko 
63032a437dbSMikhail Rudenko 	if (n == ARRAY_SIZE(ov4689_gain_ranges)) {
63132a437dbSMikhail Rudenko 		dev_warn_ratelimited(dev, "no mapping found for gain %d\n",
63232a437dbSMikhail Rudenko 				     logical_gain);
63332a437dbSMikhail Rudenko 		return -EINVAL;
63432a437dbSMikhail Rudenko 	}
63532a437dbSMikhail Rudenko 
63632a437dbSMikhail Rudenko 	range = &ov4689_gain_ranges[n];
63732a437dbSMikhail Rudenko 
63832a437dbSMikhail Rudenko 	*result = clamp(range->offset + (logical_gain) / range->divider,
63932a437dbSMikhail Rudenko 			range->physical_min, range->physical_max);
64032a437dbSMikhail Rudenko 	return 0;
64132a437dbSMikhail Rudenko }
64232a437dbSMikhail Rudenko 
ov4689_set_ctrl(struct v4l2_ctrl * ctrl)64332a437dbSMikhail Rudenko static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl)
64432a437dbSMikhail Rudenko {
64532a437dbSMikhail Rudenko 	struct ov4689 *ov4689 =
64632a437dbSMikhail Rudenko 		container_of(ctrl->handler, struct ov4689, ctrl_handler);
64732a437dbSMikhail Rudenko 	struct i2c_client *client = ov4689->client;
64832a437dbSMikhail Rudenko 	int sensor_gain;
64932a437dbSMikhail Rudenko 	s64 max_expo;
65032a437dbSMikhail Rudenko 	int ret;
65132a437dbSMikhail Rudenko 
65232a437dbSMikhail Rudenko 	/* Propagate change of current control to all related controls */
65332a437dbSMikhail Rudenko 	switch (ctrl->id) {
65432a437dbSMikhail Rudenko 	case V4L2_CID_VBLANK:
65532a437dbSMikhail Rudenko 		/* Update max exposure while meeting expected vblanking */
65632a437dbSMikhail Rudenko 		max_expo = ov4689->cur_mode->height + ctrl->val - 4;
65732a437dbSMikhail Rudenko 		__v4l2_ctrl_modify_range(ov4689->exposure,
65832a437dbSMikhail Rudenko 					 ov4689->exposure->minimum, max_expo,
65932a437dbSMikhail Rudenko 					 ov4689->exposure->step,
66032a437dbSMikhail Rudenko 					 ov4689->exposure->default_value);
66132a437dbSMikhail Rudenko 		break;
66232a437dbSMikhail Rudenko 	}
66332a437dbSMikhail Rudenko 
66432a437dbSMikhail Rudenko 	if (!pm_runtime_get_if_in_use(&client->dev))
66532a437dbSMikhail Rudenko 		return 0;
66632a437dbSMikhail Rudenko 
66732a437dbSMikhail Rudenko 	switch (ctrl->id) {
66832a437dbSMikhail Rudenko 	case V4L2_CID_EXPOSURE:
66932a437dbSMikhail Rudenko 		/* 4 least significant bits of expsoure are fractional part */
67032a437dbSMikhail Rudenko 		ret = ov4689_write_reg(ov4689->client, OV4689_REG_EXPOSURE,
67132a437dbSMikhail Rudenko 				       OV4689_REG_VALUE_24BIT, ctrl->val << 4);
67232a437dbSMikhail Rudenko 		break;
67332a437dbSMikhail Rudenko 	case V4L2_CID_ANALOGUE_GAIN:
67432a437dbSMikhail Rudenko 		ret = ov4689_map_gain(ov4689, ctrl->val, &sensor_gain);
67532a437dbSMikhail Rudenko 
67632a437dbSMikhail Rudenko 		ret = ret ?:
67732a437dbSMikhail Rudenko 			ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_H,
67832a437dbSMikhail Rudenko 					 OV4689_REG_VALUE_08BIT,
67932a437dbSMikhail Rudenko 					 (sensor_gain >> OV4689_GAIN_H_SHIFT) &
68032a437dbSMikhail Rudenko 					 OV4689_GAIN_H_MASK);
68132a437dbSMikhail Rudenko 		ret = ret ?:
68232a437dbSMikhail Rudenko 			ov4689_write_reg(ov4689->client, OV4689_REG_GAIN_L,
68332a437dbSMikhail Rudenko 					 OV4689_REG_VALUE_08BIT,
68432a437dbSMikhail Rudenko 					 sensor_gain & OV4689_GAIN_L_MASK);
68532a437dbSMikhail Rudenko 		break;
68632a437dbSMikhail Rudenko 	case V4L2_CID_VBLANK:
68732a437dbSMikhail Rudenko 		ret = ov4689_write_reg(ov4689->client, OV4689_REG_VTS,
68832a437dbSMikhail Rudenko 				       OV4689_REG_VALUE_16BIT,
68932a437dbSMikhail Rudenko 				       ctrl->val + ov4689->cur_mode->height);
69032a437dbSMikhail Rudenko 		break;
69132a437dbSMikhail Rudenko 	case V4L2_CID_TEST_PATTERN:
69232a437dbSMikhail Rudenko 		ret = ov4689_enable_test_pattern(ov4689, ctrl->val);
69332a437dbSMikhail Rudenko 		break;
69432a437dbSMikhail Rudenko 	default:
69532a437dbSMikhail Rudenko 		dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n",
69632a437dbSMikhail Rudenko 			 __func__, ctrl->id, ctrl->val);
69732a437dbSMikhail Rudenko 		ret = -EINVAL;
69832a437dbSMikhail Rudenko 		break;
69932a437dbSMikhail Rudenko 	}
70032a437dbSMikhail Rudenko 
70132a437dbSMikhail Rudenko 	pm_runtime_put(&client->dev);
70232a437dbSMikhail Rudenko 
70332a437dbSMikhail Rudenko 	return ret;
70432a437dbSMikhail Rudenko }
70532a437dbSMikhail Rudenko 
70632a437dbSMikhail Rudenko static const struct v4l2_ctrl_ops ov4689_ctrl_ops = {
70732a437dbSMikhail Rudenko 	.s_ctrl = ov4689_set_ctrl,
70832a437dbSMikhail Rudenko };
70932a437dbSMikhail Rudenko 
ov4689_initialize_controls(struct ov4689 * ov4689)71032a437dbSMikhail Rudenko static int ov4689_initialize_controls(struct ov4689 *ov4689)
71132a437dbSMikhail Rudenko {
71232a437dbSMikhail Rudenko 	struct i2c_client *client = v4l2_get_subdevdata(&ov4689->subdev);
71332a437dbSMikhail Rudenko 	struct v4l2_fwnode_device_properties props;
71432a437dbSMikhail Rudenko 	struct v4l2_ctrl_handler *handler;
71532a437dbSMikhail Rudenko 	const struct ov4689_mode *mode;
71632a437dbSMikhail Rudenko 	s64 exposure_max, vblank_def;
71732a437dbSMikhail Rudenko 	struct v4l2_ctrl *ctrl;
71832a437dbSMikhail Rudenko 	s64 h_blank_def;
71932a437dbSMikhail Rudenko 	int ret;
72032a437dbSMikhail Rudenko 
72132a437dbSMikhail Rudenko 	handler = &ov4689->ctrl_handler;
72232a437dbSMikhail Rudenko 	mode = ov4689->cur_mode;
72332a437dbSMikhail Rudenko 	ret = v4l2_ctrl_handler_init(handler, 10);
72432a437dbSMikhail Rudenko 	if (ret)
72532a437dbSMikhail Rudenko 		return ret;
72632a437dbSMikhail Rudenko 	handler->lock = &ov4689->mutex;
72732a437dbSMikhail Rudenko 
72832a437dbSMikhail Rudenko 	ctrl = v4l2_ctrl_new_int_menu(handler, NULL, V4L2_CID_LINK_FREQ, 0, 0,
72932a437dbSMikhail Rudenko 				      link_freq_menu_items);
73032a437dbSMikhail Rudenko 	if (ctrl)
73132a437dbSMikhail Rudenko 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
73232a437dbSMikhail Rudenko 
73332a437dbSMikhail Rudenko 	v4l2_ctrl_new_std(handler, NULL, V4L2_CID_PIXEL_RATE, 0,
73432a437dbSMikhail Rudenko 			  mode->pixel_rate, 1, mode->pixel_rate);
73532a437dbSMikhail Rudenko 
73632a437dbSMikhail Rudenko 	h_blank_def = mode->hts_def - mode->width;
73732a437dbSMikhail Rudenko 	ctrl = v4l2_ctrl_new_std(handler, NULL, V4L2_CID_HBLANK, h_blank_def,
73832a437dbSMikhail Rudenko 				 h_blank_def, 1, h_blank_def);
73932a437dbSMikhail Rudenko 	if (ctrl)
74032a437dbSMikhail Rudenko 		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
74132a437dbSMikhail Rudenko 
74232a437dbSMikhail Rudenko 	vblank_def = mode->vts_def - mode->height;
74332a437dbSMikhail Rudenko 	v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_VBLANK,
74432a437dbSMikhail Rudenko 			  vblank_def, OV4689_VTS_MAX - mode->height, 1,
74532a437dbSMikhail Rudenko 			  vblank_def);
74632a437dbSMikhail Rudenko 
74732a437dbSMikhail Rudenko 	exposure_max = mode->vts_def - 4;
74832a437dbSMikhail Rudenko 	ov4689->exposure =
74932a437dbSMikhail Rudenko 		v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_EXPOSURE,
75032a437dbSMikhail Rudenko 				  OV4689_EXPOSURE_MIN, exposure_max,
75132a437dbSMikhail Rudenko 				  OV4689_EXPOSURE_STEP, mode->exp_def);
75232a437dbSMikhail Rudenko 
75332a437dbSMikhail Rudenko 	v4l2_ctrl_new_std(handler, &ov4689_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
75432a437dbSMikhail Rudenko 			  ov4689_gain_ranges[0].logical_min,
75532a437dbSMikhail Rudenko 			  ov4689_gain_ranges[ARRAY_SIZE(ov4689_gain_ranges) - 1]
75632a437dbSMikhail Rudenko 				  .logical_max,
75732a437dbSMikhail Rudenko 			  OV4689_GAIN_STEP, OV4689_GAIN_DEFAULT);
75832a437dbSMikhail Rudenko 
75932a437dbSMikhail Rudenko 	v4l2_ctrl_new_std_menu_items(handler, &ov4689_ctrl_ops,
76032a437dbSMikhail Rudenko 				     V4L2_CID_TEST_PATTERN,
76132a437dbSMikhail Rudenko 				     ARRAY_SIZE(ov4689_test_pattern_menu) - 1,
76232a437dbSMikhail Rudenko 				     0, 0, ov4689_test_pattern_menu);
76332a437dbSMikhail Rudenko 
76432a437dbSMikhail Rudenko 	if (handler->error) {
76532a437dbSMikhail Rudenko 		ret = handler->error;
76632a437dbSMikhail Rudenko 		dev_err(&ov4689->client->dev, "Failed to init controls(%d)\n",
76732a437dbSMikhail Rudenko 			ret);
76832a437dbSMikhail Rudenko 		goto err_free_handler;
76932a437dbSMikhail Rudenko 	}
77032a437dbSMikhail Rudenko 
77132a437dbSMikhail Rudenko 	ret = v4l2_fwnode_device_parse(&client->dev, &props);
77232a437dbSMikhail Rudenko 	if (ret)
77332a437dbSMikhail Rudenko 		goto err_free_handler;
77432a437dbSMikhail Rudenko 
77532a437dbSMikhail Rudenko 	ret = v4l2_ctrl_new_fwnode_properties(handler, &ov4689_ctrl_ops,
77632a437dbSMikhail Rudenko 					      &props);
77732a437dbSMikhail Rudenko 	if (ret)
77832a437dbSMikhail Rudenko 		goto err_free_handler;
77932a437dbSMikhail Rudenko 
78032a437dbSMikhail Rudenko 	ov4689->subdev.ctrl_handler = handler;
78132a437dbSMikhail Rudenko 
78232a437dbSMikhail Rudenko 	return 0;
78332a437dbSMikhail Rudenko 
78432a437dbSMikhail Rudenko err_free_handler:
78532a437dbSMikhail Rudenko 	v4l2_ctrl_handler_free(handler);
78632a437dbSMikhail Rudenko 
78732a437dbSMikhail Rudenko 	return ret;
78832a437dbSMikhail Rudenko }
78932a437dbSMikhail Rudenko 
ov4689_check_sensor_id(struct ov4689 * ov4689,struct i2c_client * client)79032a437dbSMikhail Rudenko static int ov4689_check_sensor_id(struct ov4689 *ov4689,
79132a437dbSMikhail Rudenko 				  struct i2c_client *client)
79232a437dbSMikhail Rudenko {
79332a437dbSMikhail Rudenko 	struct device *dev = &ov4689->client->dev;
79432a437dbSMikhail Rudenko 	u32 id = 0;
79532a437dbSMikhail Rudenko 	int ret;
79632a437dbSMikhail Rudenko 
79732a437dbSMikhail Rudenko 	ret = ov4689_read_reg(client, OV4689_REG_CHIP_ID,
79832a437dbSMikhail Rudenko 			      OV4689_REG_VALUE_16BIT, &id);
79932a437dbSMikhail Rudenko 	if (ret) {
80032a437dbSMikhail Rudenko 		dev_err(dev, "Cannot read sensor ID\n");
80132a437dbSMikhail Rudenko 		return ret;
80232a437dbSMikhail Rudenko 	}
80332a437dbSMikhail Rudenko 
80432a437dbSMikhail Rudenko 	if (id != CHIP_ID) {
80532a437dbSMikhail Rudenko 		dev_err(dev, "Unexpected sensor ID %06x, expected %06x\n",
80632a437dbSMikhail Rudenko 			id, CHIP_ID);
80732a437dbSMikhail Rudenko 		return -ENODEV;
80832a437dbSMikhail Rudenko 	}
80932a437dbSMikhail Rudenko 
81032a437dbSMikhail Rudenko 	dev_info(dev, "Detected OV%06x sensor\n", CHIP_ID);
81132a437dbSMikhail Rudenko 
81232a437dbSMikhail Rudenko 	return 0;
81332a437dbSMikhail Rudenko }
81432a437dbSMikhail Rudenko 
ov4689_configure_regulators(struct ov4689 * ov4689)81532a437dbSMikhail Rudenko static int ov4689_configure_regulators(struct ov4689 *ov4689)
81632a437dbSMikhail Rudenko {
81732a437dbSMikhail Rudenko 	unsigned int i;
81832a437dbSMikhail Rudenko 
8197336c54aSMikhail Rudenko 	for (i = 0; i < ARRAY_SIZE(ov4689_supply_names); i++)
82032a437dbSMikhail Rudenko 		ov4689->supplies[i].supply = ov4689_supply_names[i];
82132a437dbSMikhail Rudenko 
8227336c54aSMikhail Rudenko 	return devm_regulator_bulk_get(&ov4689->client->dev,
8237336c54aSMikhail Rudenko 				       ARRAY_SIZE(ov4689_supply_names),
82432a437dbSMikhail Rudenko 				       ov4689->supplies);
82532a437dbSMikhail Rudenko }
82632a437dbSMikhail Rudenko 
ov4689_check_link_frequency(struct v4l2_fwnode_endpoint * ep)82732a437dbSMikhail Rudenko static u64 ov4689_check_link_frequency(struct v4l2_fwnode_endpoint *ep)
82832a437dbSMikhail Rudenko {
82932a437dbSMikhail Rudenko 	const u64 *freqs = link_freq_menu_items;
83032a437dbSMikhail Rudenko 	unsigned int i, j;
83132a437dbSMikhail Rudenko 
8327336c54aSMikhail Rudenko 	for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) {
83332a437dbSMikhail Rudenko 		for (j = 0; j < ep->nr_of_link_frequencies; j++)
83432a437dbSMikhail Rudenko 			if (freqs[i] == ep->link_frequencies[j])
83532a437dbSMikhail Rudenko 				return freqs[i];
83632a437dbSMikhail Rudenko 	}
83732a437dbSMikhail Rudenko 
83832a437dbSMikhail Rudenko 	return 0;
83932a437dbSMikhail Rudenko }
84032a437dbSMikhail Rudenko 
ov4689_check_hwcfg(struct device * dev)84132a437dbSMikhail Rudenko static int ov4689_check_hwcfg(struct device *dev)
84232a437dbSMikhail Rudenko {
84332a437dbSMikhail Rudenko 	struct fwnode_handle *fwnode = dev_fwnode(dev);
84432a437dbSMikhail Rudenko 	struct v4l2_fwnode_endpoint bus_cfg = {
84532a437dbSMikhail Rudenko 		.bus_type = V4L2_MBUS_CSI2_DPHY,
84632a437dbSMikhail Rudenko 	};
84732a437dbSMikhail Rudenko 	struct fwnode_handle *endpoint;
84832a437dbSMikhail Rudenko 	int ret;
84932a437dbSMikhail Rudenko 
85032a437dbSMikhail Rudenko 	endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
85132a437dbSMikhail Rudenko 	if (!endpoint)
85232a437dbSMikhail Rudenko 		return -EINVAL;
85332a437dbSMikhail Rudenko 
85432a437dbSMikhail Rudenko 	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
85532a437dbSMikhail Rudenko 	fwnode_handle_put(endpoint);
85632a437dbSMikhail Rudenko 	if (ret)
85732a437dbSMikhail Rudenko 		return ret;
85832a437dbSMikhail Rudenko 
85932a437dbSMikhail Rudenko 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV4689_LANES) {
86032a437dbSMikhail Rudenko 		dev_err(dev, "Only a 4-lane CSI2 config is supported");
86132a437dbSMikhail Rudenko 		ret = -EINVAL;
86232a437dbSMikhail Rudenko 		goto out_free_bus_cfg;
86332a437dbSMikhail Rudenko 	}
86432a437dbSMikhail Rudenko 
86532a437dbSMikhail Rudenko 	if (!ov4689_check_link_frequency(&bus_cfg)) {
86632a437dbSMikhail Rudenko 		dev_err(dev, "No supported link frequency found\n");
86732a437dbSMikhail Rudenko 		ret = -EINVAL;
86832a437dbSMikhail Rudenko 	}
86932a437dbSMikhail Rudenko 
87032a437dbSMikhail Rudenko out_free_bus_cfg:
87132a437dbSMikhail Rudenko 	v4l2_fwnode_endpoint_free(&bus_cfg);
87232a437dbSMikhail Rudenko 
87332a437dbSMikhail Rudenko 	return ret;
87432a437dbSMikhail Rudenko }
87532a437dbSMikhail Rudenko 
ov4689_probe(struct i2c_client * client)87632a437dbSMikhail Rudenko static int ov4689_probe(struct i2c_client *client)
87732a437dbSMikhail Rudenko {
87832a437dbSMikhail Rudenko 	struct device *dev = &client->dev;
87932a437dbSMikhail Rudenko 	struct v4l2_subdev *sd;
88032a437dbSMikhail Rudenko 	struct ov4689 *ov4689;
88132a437dbSMikhail Rudenko 	int ret;
88232a437dbSMikhail Rudenko 
88332a437dbSMikhail Rudenko 	ret = ov4689_check_hwcfg(dev);
88432a437dbSMikhail Rudenko 	if (ret)
88532a437dbSMikhail Rudenko 		return ret;
88632a437dbSMikhail Rudenko 
88732a437dbSMikhail Rudenko 	ov4689 = devm_kzalloc(dev, sizeof(*ov4689), GFP_KERNEL);
88832a437dbSMikhail Rudenko 	if (!ov4689)
88932a437dbSMikhail Rudenko 		return -ENOMEM;
89032a437dbSMikhail Rudenko 
89132a437dbSMikhail Rudenko 	ov4689->client = client;
89232a437dbSMikhail Rudenko 	ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520];
89332a437dbSMikhail Rudenko 
89432a437dbSMikhail Rudenko 	ov4689->xvclk = devm_clk_get_optional(dev, NULL);
89532a437dbSMikhail Rudenko 	if (IS_ERR(ov4689->xvclk))
89632a437dbSMikhail Rudenko 		return dev_err_probe(dev, PTR_ERR(ov4689->xvclk),
89732a437dbSMikhail Rudenko 				     "Failed to get external clock\n");
89832a437dbSMikhail Rudenko 
89932a437dbSMikhail Rudenko 	if (!ov4689->xvclk) {
90032a437dbSMikhail Rudenko 		dev_dbg(dev,
90132a437dbSMikhail Rudenko 			"No clock provided, using clock-frequency property\n");
90232a437dbSMikhail Rudenko 		device_property_read_u32(dev, "clock-frequency",
90332a437dbSMikhail Rudenko 					 &ov4689->clock_rate);
90432a437dbSMikhail Rudenko 	} else {
90532a437dbSMikhail Rudenko 		ov4689->clock_rate = clk_get_rate(ov4689->xvclk);
90632a437dbSMikhail Rudenko 	}
90732a437dbSMikhail Rudenko 
90832a437dbSMikhail Rudenko 	if (ov4689->clock_rate != OV4689_XVCLK_FREQ) {
90932a437dbSMikhail Rudenko 		dev_err(dev,
91032a437dbSMikhail Rudenko 			"External clock rate mismatch: got %d Hz, expected %d Hz\n",
91132a437dbSMikhail Rudenko 			ov4689->clock_rate, OV4689_XVCLK_FREQ);
91232a437dbSMikhail Rudenko 		return -EINVAL;
91332a437dbSMikhail Rudenko 	}
91432a437dbSMikhail Rudenko 
91532a437dbSMikhail Rudenko 	ov4689->reset_gpio = devm_gpiod_get_optional(dev, "reset",
91632a437dbSMikhail Rudenko 						     GPIOD_OUT_LOW);
91732a437dbSMikhail Rudenko 	if (IS_ERR(ov4689->reset_gpio)) {
91832a437dbSMikhail Rudenko 		dev_err(dev, "Failed to get reset-gpios\n");
91932a437dbSMikhail Rudenko 		return PTR_ERR(ov4689->reset_gpio);
92032a437dbSMikhail Rudenko 	}
92132a437dbSMikhail Rudenko 
92232a437dbSMikhail Rudenko 	ov4689->pwdn_gpio = devm_gpiod_get_optional(dev, "pwdn", GPIOD_OUT_LOW);
92332a437dbSMikhail Rudenko 	if (IS_ERR(ov4689->pwdn_gpio)) {
92432a437dbSMikhail Rudenko 		dev_err(dev, "Failed to get pwdn-gpios\n");
92532a437dbSMikhail Rudenko 		return PTR_ERR(ov4689->pwdn_gpio);
92632a437dbSMikhail Rudenko 	}
92732a437dbSMikhail Rudenko 
92832a437dbSMikhail Rudenko 	ret = ov4689_configure_regulators(ov4689);
92932a437dbSMikhail Rudenko 	if (ret)
93032a437dbSMikhail Rudenko 		return dev_err_probe(dev, ret,
93132a437dbSMikhail Rudenko 				     "Failed to get power regulators\n");
93232a437dbSMikhail Rudenko 
93332a437dbSMikhail Rudenko 	mutex_init(&ov4689->mutex);
93432a437dbSMikhail Rudenko 
93532a437dbSMikhail Rudenko 	sd = &ov4689->subdev;
93632a437dbSMikhail Rudenko 	v4l2_i2c_subdev_init(sd, client, &ov4689_subdev_ops);
93732a437dbSMikhail Rudenko 	ret = ov4689_initialize_controls(ov4689);
93832a437dbSMikhail Rudenko 	if (ret)
93932a437dbSMikhail Rudenko 		goto err_destroy_mutex;
94032a437dbSMikhail Rudenko 
94132a437dbSMikhail Rudenko 	ret = ov4689_power_on(dev);
94232a437dbSMikhail Rudenko 	if (ret)
94332a437dbSMikhail Rudenko 		goto err_free_handler;
94432a437dbSMikhail Rudenko 
94532a437dbSMikhail Rudenko 	ret = ov4689_check_sensor_id(ov4689, client);
94632a437dbSMikhail Rudenko 	if (ret)
94732a437dbSMikhail Rudenko 		goto err_power_off;
94832a437dbSMikhail Rudenko 
94932a437dbSMikhail Rudenko 	sd->internal_ops = &ov4689_internal_ops;
95032a437dbSMikhail Rudenko 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
95132a437dbSMikhail Rudenko 
95232a437dbSMikhail Rudenko 	ov4689->pad.flags = MEDIA_PAD_FL_SOURCE;
95332a437dbSMikhail Rudenko 	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
95432a437dbSMikhail Rudenko 	ret = media_entity_pads_init(&sd->entity, 1, &ov4689->pad);
95532a437dbSMikhail Rudenko 	if (ret < 0)
95632a437dbSMikhail Rudenko 		goto err_power_off;
95732a437dbSMikhail Rudenko 
95832a437dbSMikhail Rudenko 	ret = v4l2_async_register_subdev_sensor(sd);
95932a437dbSMikhail Rudenko 	if (ret) {
96032a437dbSMikhail Rudenko 		dev_err(dev, "v4l2 async register subdev failed\n");
96132a437dbSMikhail Rudenko 		goto err_clean_entity;
96232a437dbSMikhail Rudenko 	}
96332a437dbSMikhail Rudenko 
96432a437dbSMikhail Rudenko 	pm_runtime_set_active(dev);
96532a437dbSMikhail Rudenko 	pm_runtime_enable(dev);
96632a437dbSMikhail Rudenko 	pm_runtime_idle(dev);
96732a437dbSMikhail Rudenko 
96832a437dbSMikhail Rudenko 	return 0;
96932a437dbSMikhail Rudenko 
97032a437dbSMikhail Rudenko err_clean_entity:
97132a437dbSMikhail Rudenko 	media_entity_cleanup(&sd->entity);
97232a437dbSMikhail Rudenko err_power_off:
97332a437dbSMikhail Rudenko 	ov4689_power_off(dev);
97432a437dbSMikhail Rudenko err_free_handler:
97532a437dbSMikhail Rudenko 	v4l2_ctrl_handler_free(&ov4689->ctrl_handler);
97632a437dbSMikhail Rudenko err_destroy_mutex:
97732a437dbSMikhail Rudenko 	mutex_destroy(&ov4689->mutex);
97832a437dbSMikhail Rudenko 
97932a437dbSMikhail Rudenko 	return ret;
98032a437dbSMikhail Rudenko }
98132a437dbSMikhail Rudenko 
ov4689_remove(struct i2c_client * client)98232a437dbSMikhail Rudenko static void ov4689_remove(struct i2c_client *client)
98332a437dbSMikhail Rudenko {
98432a437dbSMikhail Rudenko 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
98532a437dbSMikhail Rudenko 	struct ov4689 *ov4689 = to_ov4689(sd);
98632a437dbSMikhail Rudenko 
98732a437dbSMikhail Rudenko 	v4l2_async_unregister_subdev(sd);
98832a437dbSMikhail Rudenko 	media_entity_cleanup(&sd->entity);
98932a437dbSMikhail Rudenko 
99032a437dbSMikhail Rudenko 	v4l2_ctrl_handler_free(&ov4689->ctrl_handler);
99132a437dbSMikhail Rudenko 	mutex_destroy(&ov4689->mutex);
99232a437dbSMikhail Rudenko 
99332a437dbSMikhail Rudenko 	pm_runtime_disable(&client->dev);
99432a437dbSMikhail Rudenko 	if (!pm_runtime_status_suspended(&client->dev))
99532a437dbSMikhail Rudenko 		ov4689_power_off(&client->dev);
99632a437dbSMikhail Rudenko 	pm_runtime_set_suspended(&client->dev);
99732a437dbSMikhail Rudenko }
99832a437dbSMikhail Rudenko 
99932a437dbSMikhail Rudenko static const struct of_device_id ov4689_of_match[] = {
100032a437dbSMikhail Rudenko 	{ .compatible = "ovti,ov4689" },
100132a437dbSMikhail Rudenko 	{},
100232a437dbSMikhail Rudenko };
100332a437dbSMikhail Rudenko MODULE_DEVICE_TABLE(of, ov4689_of_match);
100432a437dbSMikhail Rudenko 
100532a437dbSMikhail Rudenko static struct i2c_driver ov4689_i2c_driver = {
100632a437dbSMikhail Rudenko 	.driver = {
100732a437dbSMikhail Rudenko 		.name = "ov4689",
100832a437dbSMikhail Rudenko 		.pm = &ov4689_pm_ops,
100932a437dbSMikhail Rudenko 		.of_match_table = ov4689_of_match,
101032a437dbSMikhail Rudenko 	},
1011*aaeb31c0SUwe Kleine-König 	.probe = ov4689_probe,
101232a437dbSMikhail Rudenko 	.remove	= ov4689_remove,
101332a437dbSMikhail Rudenko };
101432a437dbSMikhail Rudenko 
101532a437dbSMikhail Rudenko module_i2c_driver(ov4689_i2c_driver);
101632a437dbSMikhail Rudenko 
101732a437dbSMikhail Rudenko MODULE_DESCRIPTION("OmniVision ov4689 sensor driver");
101832a437dbSMikhail Rudenko MODULE_LICENSE("GPL");
1019