xref: /openbmc/linux/drivers/media/i2c/ov9282.c (revision 995809ce)
114ea315bSMartina Krasteva // SPDX-License-Identifier: GPL-2.0-only
214ea315bSMartina Krasteva /*
314ea315bSMartina Krasteva  * OmniVision ov9282 Camera Sensor Driver
414ea315bSMartina Krasteva  *
514ea315bSMartina Krasteva  * Copyright (C) 2021 Intel Corporation
614ea315bSMartina Krasteva  */
714ea315bSMartina Krasteva #include <asm/unaligned.h>
814ea315bSMartina Krasteva 
914ea315bSMartina Krasteva #include <linux/clk.h>
1014ea315bSMartina Krasteva #include <linux/delay.h>
1114ea315bSMartina Krasteva #include <linux/i2c.h>
1214ea315bSMartina Krasteva #include <linux/module.h>
1314ea315bSMartina Krasteva #include <linux/pm_runtime.h>
1414ea315bSMartina Krasteva 
1514ea315bSMartina Krasteva #include <media/v4l2-ctrls.h>
1614ea315bSMartina Krasteva #include <media/v4l2-fwnode.h>
1714ea315bSMartina Krasteva #include <media/v4l2-subdev.h>
1814ea315bSMartina Krasteva 
1914ea315bSMartina Krasteva /* Streaming Mode */
2014ea315bSMartina Krasteva #define OV9282_REG_MODE_SELECT	0x0100
2114ea315bSMartina Krasteva #define OV9282_MODE_STANDBY	0x00
2214ea315bSMartina Krasteva #define OV9282_MODE_STREAMING	0x01
2314ea315bSMartina Krasteva 
2414ea315bSMartina Krasteva /* Lines per frame */
2514ea315bSMartina Krasteva #define OV9282_REG_LPFR		0x380e
2614ea315bSMartina Krasteva 
2714ea315bSMartina Krasteva /* Chip ID */
2814ea315bSMartina Krasteva #define OV9282_REG_ID		0x300a
2914ea315bSMartina Krasteva #define OV9282_ID		0x9281
3014ea315bSMartina Krasteva 
3114ea315bSMartina Krasteva /* Exposure control */
3214ea315bSMartina Krasteva #define OV9282_REG_EXPOSURE	0x3500
3314ea315bSMartina Krasteva #define OV9282_EXPOSURE_MIN	1
3414ea315bSMartina Krasteva #define OV9282_EXPOSURE_OFFSET	12
3514ea315bSMartina Krasteva #define OV9282_EXPOSURE_STEP	1
3614ea315bSMartina Krasteva #define OV9282_EXPOSURE_DEFAULT	0x0282
3714ea315bSMartina Krasteva 
3814ea315bSMartina Krasteva /* Analog gain control */
3914ea315bSMartina Krasteva #define OV9282_REG_AGAIN	0x3509
4014ea315bSMartina Krasteva #define OV9282_AGAIN_MIN	0x10
4114ea315bSMartina Krasteva #define OV9282_AGAIN_MAX	0xff
4214ea315bSMartina Krasteva #define OV9282_AGAIN_STEP	1
4314ea315bSMartina Krasteva #define OV9282_AGAIN_DEFAULT	0x10
4414ea315bSMartina Krasteva 
4514ea315bSMartina Krasteva /* Group hold register */
4614ea315bSMartina Krasteva #define OV9282_REG_HOLD		0x3308
4714ea315bSMartina Krasteva 
4814ea315bSMartina Krasteva /* Input clock rate */
4914ea315bSMartina Krasteva #define OV9282_INCLK_RATE	24000000
5014ea315bSMartina Krasteva 
5114ea315bSMartina Krasteva /* CSI2 HW configuration */
5214ea315bSMartina Krasteva #define OV9282_LINK_FREQ	400000000
5314ea315bSMartina Krasteva #define OV9282_NUM_DATA_LANES	2
5414ea315bSMartina Krasteva 
55f15b0612SDave Stevenson /* Pixel rate */
56f15b0612SDave Stevenson #define OV9282_PIXEL_RATE	(OV9282_LINK_FREQ * 2 * \
57f15b0612SDave Stevenson 				 OV9282_NUM_DATA_LANES / 10)
58f15b0612SDave Stevenson 
5914ea315bSMartina Krasteva #define OV9282_REG_MIN		0x00
6014ea315bSMartina Krasteva #define OV9282_REG_MAX		0xfffff
6114ea315bSMartina Krasteva 
6214ea315bSMartina Krasteva /**
6314ea315bSMartina Krasteva  * struct ov9282_reg - ov9282 sensor register
6414ea315bSMartina Krasteva  * @address: Register address
6514ea315bSMartina Krasteva  * @val: Register value
6614ea315bSMartina Krasteva  */
6714ea315bSMartina Krasteva struct ov9282_reg {
6814ea315bSMartina Krasteva 	u16 address;
6914ea315bSMartina Krasteva 	u8 val;
7014ea315bSMartina Krasteva };
7114ea315bSMartina Krasteva 
7214ea315bSMartina Krasteva /**
7314ea315bSMartina Krasteva  * struct ov9282_reg_list - ov9282 sensor register list
7414ea315bSMartina Krasteva  * @num_of_regs: Number of registers in the list
7514ea315bSMartina Krasteva  * @regs: Pointer to register list
7614ea315bSMartina Krasteva  */
7714ea315bSMartina Krasteva struct ov9282_reg_list {
7814ea315bSMartina Krasteva 	u32 num_of_regs;
7914ea315bSMartina Krasteva 	const struct ov9282_reg *regs;
8014ea315bSMartina Krasteva };
8114ea315bSMartina Krasteva 
8214ea315bSMartina Krasteva /**
8314ea315bSMartina Krasteva  * struct ov9282_mode - ov9282 sensor mode structure
8414ea315bSMartina Krasteva  * @width: Frame width
8514ea315bSMartina Krasteva  * @height: Frame height
8614ea315bSMartina Krasteva  * @hblank: Horizontal blanking in lines
8714ea315bSMartina Krasteva  * @vblank: Vertical blanking in lines
8814ea315bSMartina Krasteva  * @vblank_min: Minimum vertical blanking in lines
8914ea315bSMartina Krasteva  * @vblank_max: Maximum vertical blanking in lines
9014ea315bSMartina Krasteva  * @link_freq_idx: Link frequency index
9114ea315bSMartina Krasteva  * @reg_list: Register list for sensor mode
9214ea315bSMartina Krasteva  */
9314ea315bSMartina Krasteva struct ov9282_mode {
9414ea315bSMartina Krasteva 	u32 width;
9514ea315bSMartina Krasteva 	u32 height;
9614ea315bSMartina Krasteva 	u32 hblank;
9714ea315bSMartina Krasteva 	u32 vblank;
9814ea315bSMartina Krasteva 	u32 vblank_min;
9914ea315bSMartina Krasteva 	u32 vblank_max;
10014ea315bSMartina Krasteva 	u32 link_freq_idx;
10114ea315bSMartina Krasteva 	struct ov9282_reg_list reg_list;
10214ea315bSMartina Krasteva };
10314ea315bSMartina Krasteva 
10414ea315bSMartina Krasteva /**
10514ea315bSMartina Krasteva  * struct ov9282 - ov9282 sensor device structure
10614ea315bSMartina Krasteva  * @dev: Pointer to generic device
10714ea315bSMartina Krasteva  * @client: Pointer to i2c client
10814ea315bSMartina Krasteva  * @sd: V4L2 sub-device
10914ea315bSMartina Krasteva  * @pad: Media pad. Only one pad supported
11014ea315bSMartina Krasteva  * @reset_gpio: Sensor reset gpio
11114ea315bSMartina Krasteva  * @inclk: Sensor input clock
11214ea315bSMartina Krasteva  * @ctrl_handler: V4L2 control handler
11314ea315bSMartina Krasteva  * @link_freq_ctrl: Pointer to link frequency control
11414ea315bSMartina Krasteva  * @hblank_ctrl: Pointer to horizontal blanking control
11514ea315bSMartina Krasteva  * @vblank_ctrl: Pointer to vertical blanking control
11614ea315bSMartina Krasteva  * @exp_ctrl: Pointer to exposure control
11714ea315bSMartina Krasteva  * @again_ctrl: Pointer to analog gain control
11814ea315bSMartina Krasteva  * @vblank: Vertical blanking in lines
11914ea315bSMartina Krasteva  * @cur_mode: Pointer to current selected sensor mode
12014ea315bSMartina Krasteva  * @mutex: Mutex for serializing sensor controls
12114ea315bSMartina Krasteva  * @streaming: Flag indicating streaming state
12214ea315bSMartina Krasteva  */
12314ea315bSMartina Krasteva struct ov9282 {
12414ea315bSMartina Krasteva 	struct device *dev;
12514ea315bSMartina Krasteva 	struct i2c_client *client;
12614ea315bSMartina Krasteva 	struct v4l2_subdev sd;
12714ea315bSMartina Krasteva 	struct media_pad pad;
12814ea315bSMartina Krasteva 	struct gpio_desc *reset_gpio;
12914ea315bSMartina Krasteva 	struct clk *inclk;
13014ea315bSMartina Krasteva 	struct v4l2_ctrl_handler ctrl_handler;
13114ea315bSMartina Krasteva 	struct v4l2_ctrl *link_freq_ctrl;
13214ea315bSMartina Krasteva 	struct v4l2_ctrl *hblank_ctrl;
13314ea315bSMartina Krasteva 	struct v4l2_ctrl *vblank_ctrl;
13414ea315bSMartina Krasteva 	struct {
13514ea315bSMartina Krasteva 		struct v4l2_ctrl *exp_ctrl;
13614ea315bSMartina Krasteva 		struct v4l2_ctrl *again_ctrl;
13714ea315bSMartina Krasteva 	};
13814ea315bSMartina Krasteva 	u32 vblank;
13914ea315bSMartina Krasteva 	const struct ov9282_mode *cur_mode;
14014ea315bSMartina Krasteva 	struct mutex mutex;
14114ea315bSMartina Krasteva 	bool streaming;
14214ea315bSMartina Krasteva };
14314ea315bSMartina Krasteva 
14414ea315bSMartina Krasteva static const s64 link_freq[] = {
14514ea315bSMartina Krasteva 	OV9282_LINK_FREQ,
14614ea315bSMartina Krasteva };
14714ea315bSMartina Krasteva 
1487195aabfSDave Stevenson /* Common registers */
1497195aabfSDave Stevenson static const struct ov9282_reg common_regs[] = {
15014ea315bSMartina Krasteva 	{0x0302, 0x32},
15114ea315bSMartina Krasteva 	{0x030d, 0x50},
15214ea315bSMartina Krasteva 	{0x030e, 0x02},
15314ea315bSMartina Krasteva 	{0x3001, 0x00},
15414ea315bSMartina Krasteva 	{0x3004, 0x00},
15514ea315bSMartina Krasteva 	{0x3005, 0x00},
15614ea315bSMartina Krasteva 	{0x3006, 0x04},
15714ea315bSMartina Krasteva 	{0x3011, 0x0a},
15814ea315bSMartina Krasteva 	{0x3013, 0x18},
15914ea315bSMartina Krasteva 	{0x301c, 0xf0},
16014ea315bSMartina Krasteva 	{0x3022, 0x01},
16114ea315bSMartina Krasteva 	{0x3030, 0x10},
16214ea315bSMartina Krasteva 	{0x3039, 0x32},
16314ea315bSMartina Krasteva 	{0x303a, 0x00},
16414ea315bSMartina Krasteva 	{0x3503, 0x08},
16514ea315bSMartina Krasteva 	{0x3505, 0x8c},
16614ea315bSMartina Krasteva 	{0x3507, 0x03},
16714ea315bSMartina Krasteva 	{0x3508, 0x00},
16814ea315bSMartina Krasteva 	{0x3610, 0x80},
16914ea315bSMartina Krasteva 	{0x3611, 0xa0},
17014ea315bSMartina Krasteva 	{0x3620, 0x6e},
17114ea315bSMartina Krasteva 	{0x3632, 0x56},
17214ea315bSMartina Krasteva 	{0x3633, 0x78},
17314ea315bSMartina Krasteva 	{0x3666, 0x00},
17414ea315bSMartina Krasteva 	{0x366f, 0x5a},
17514ea315bSMartina Krasteva 	{0x3680, 0x84},
17614ea315bSMartina Krasteva 	{0x3712, 0x80},
17714ea315bSMartina Krasteva 	{0x372d, 0x22},
17814ea315bSMartina Krasteva 	{0x3731, 0x80},
17914ea315bSMartina Krasteva 	{0x3732, 0x30},
18014ea315bSMartina Krasteva 	{0x377d, 0x22},
18114ea315bSMartina Krasteva 	{0x3788, 0x02},
18214ea315bSMartina Krasteva 	{0x3789, 0xa4},
18314ea315bSMartina Krasteva 	{0x378a, 0x00},
18414ea315bSMartina Krasteva 	{0x378b, 0x4a},
18514ea315bSMartina Krasteva 	{0x3799, 0x20},
1867195aabfSDave Stevenson 	{0x3881, 0x42},
1877195aabfSDave Stevenson 	{0x38a8, 0x02},
1887195aabfSDave Stevenson 	{0x38a9, 0x80},
1897195aabfSDave Stevenson 	{0x38b1, 0x00},
1907195aabfSDave Stevenson 	{0x38c4, 0x00},
1917195aabfSDave Stevenson 	{0x38c5, 0xc0},
1927195aabfSDave Stevenson 	{0x38c6, 0x04},
1937195aabfSDave Stevenson 	{0x38c7, 0x80},
1947195aabfSDave Stevenson 	{0x3920, 0xff},
1957195aabfSDave Stevenson 	{0x4010, 0x40},
1967195aabfSDave Stevenson 	{0x4043, 0x40},
1977195aabfSDave Stevenson 	{0x4307, 0x30},
1987195aabfSDave Stevenson 	{0x4317, 0x00},
1997195aabfSDave Stevenson 	{0x4501, 0x00},
2007195aabfSDave Stevenson 	{0x450a, 0x08},
2017195aabfSDave Stevenson 	{0x4601, 0x04},
2027195aabfSDave Stevenson 	{0x470f, 0x00},
2037195aabfSDave Stevenson 	{0x4f07, 0x00},
2047195aabfSDave Stevenson 	{0x4800, 0x20},
2057195aabfSDave Stevenson 	{0x5000, 0x9f},
2067195aabfSDave Stevenson 	{0x5001, 0x00},
2077195aabfSDave Stevenson 	{0x5e00, 0x00},
2087195aabfSDave Stevenson 	{0x5d00, 0x07},
2097195aabfSDave Stevenson 	{0x5d01, 0x00},
2107195aabfSDave Stevenson 	{0x0101, 0x01},
2117195aabfSDave Stevenson 	{0x1000, 0x03},
2127195aabfSDave Stevenson 	{0x5a08, 0x84},
2137195aabfSDave Stevenson };
2147195aabfSDave Stevenson 
2157195aabfSDave Stevenson struct ov9282_reg_list common_regs_list = {
2167195aabfSDave Stevenson 	.num_of_regs = ARRAY_SIZE(common_regs),
2177195aabfSDave Stevenson 	.regs = common_regs,
2187195aabfSDave Stevenson };
2197195aabfSDave Stevenson 
220*995809ceSDave Stevenson #define MODE_1280_720		0
221*995809ceSDave Stevenson 
222*995809ceSDave Stevenson #define DEFAULT_MODE		MODE_1280_720
223*995809ceSDave Stevenson 
2247195aabfSDave Stevenson /* Sensor mode registers */
2257195aabfSDave Stevenson static const struct ov9282_reg mode_1280x720_regs[] = {
2267195aabfSDave Stevenson 	{0x3778, 0x00},
22714ea315bSMartina Krasteva 	{0x3800, 0x00},
22814ea315bSMartina Krasteva 	{0x3801, 0x00},
22914ea315bSMartina Krasteva 	{0x3802, 0x00},
23014ea315bSMartina Krasteva 	{0x3803, 0x00},
23114ea315bSMartina Krasteva 	{0x3804, 0x05},
23214ea315bSMartina Krasteva 	{0x3805, 0x0f},
23314ea315bSMartina Krasteva 	{0x3806, 0x02},
23414ea315bSMartina Krasteva 	{0x3807, 0xdf},
23514ea315bSMartina Krasteva 	{0x3808, 0x05},
23614ea315bSMartina Krasteva 	{0x3809, 0x00},
23714ea315bSMartina Krasteva 	{0x380a, 0x02},
23814ea315bSMartina Krasteva 	{0x380b, 0xd0},
23914ea315bSMartina Krasteva 	{0x380c, 0x05},
24014ea315bSMartina Krasteva 	{0x380d, 0xfa},
24114ea315bSMartina Krasteva 	{0x3810, 0x00},
24214ea315bSMartina Krasteva 	{0x3811, 0x08},
24314ea315bSMartina Krasteva 	{0x3812, 0x00},
24414ea315bSMartina Krasteva 	{0x3813, 0x08},
24514ea315bSMartina Krasteva 	{0x3814, 0x11},
24614ea315bSMartina Krasteva 	{0x3815, 0x11},
24714ea315bSMartina Krasteva 	{0x3820, 0x3c},
24814ea315bSMartina Krasteva 	{0x3821, 0x84},
24914ea315bSMartina Krasteva 	{0x4003, 0x40},
25014ea315bSMartina Krasteva 	{0x4008, 0x02},
25114ea315bSMartina Krasteva 	{0x4009, 0x05},
25214ea315bSMartina Krasteva 	{0x400c, 0x00},
25314ea315bSMartina Krasteva 	{0x400d, 0x03},
25414ea315bSMartina Krasteva 	{0x4507, 0x00},
25514ea315bSMartina Krasteva 	{0x4509, 0x80},
25614ea315bSMartina Krasteva };
25714ea315bSMartina Krasteva 
25814ea315bSMartina Krasteva /* Supported sensor mode configurations */
259*995809ceSDave Stevenson static const struct ov9282_mode supported_modes[] = {
260*995809ceSDave Stevenson 	[MODE_1280_720] = {
26114ea315bSMartina Krasteva 		.width = 1280,
26214ea315bSMartina Krasteva 		.height = 720,
26314ea315bSMartina Krasteva 		.hblank = 250,
26414ea315bSMartina Krasteva 		.vblank = 1022,
26514ea315bSMartina Krasteva 		.vblank_min = 151,
26614ea315bSMartina Krasteva 		.vblank_max = 51540,
26714ea315bSMartina Krasteva 		.link_freq_idx = 0,
26814ea315bSMartina Krasteva 		.reg_list = {
26914ea315bSMartina Krasteva 			.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),
27014ea315bSMartina Krasteva 			.regs = mode_1280x720_regs,
27114ea315bSMartina Krasteva 		},
272*995809ceSDave Stevenson 	},
27314ea315bSMartina Krasteva };
27414ea315bSMartina Krasteva 
27514ea315bSMartina Krasteva /**
27614ea315bSMartina Krasteva  * to_ov9282() - ov9282 V4L2 sub-device to ov9282 device.
27714ea315bSMartina Krasteva  * @subdev: pointer to ov9282 V4L2 sub-device
27814ea315bSMartina Krasteva  *
27914ea315bSMartina Krasteva  * Return: pointer to ov9282 device
28014ea315bSMartina Krasteva  */
28114ea315bSMartina Krasteva static inline struct ov9282 *to_ov9282(struct v4l2_subdev *subdev)
28214ea315bSMartina Krasteva {
28314ea315bSMartina Krasteva 	return container_of(subdev, struct ov9282, sd);
28414ea315bSMartina Krasteva }
28514ea315bSMartina Krasteva 
28614ea315bSMartina Krasteva /**
28714ea315bSMartina Krasteva  * ov9282_read_reg() - Read registers.
28814ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
28914ea315bSMartina Krasteva  * @reg: register address
29014ea315bSMartina Krasteva  * @len: length of bytes to read. Max supported bytes is 4
29114ea315bSMartina Krasteva  * @val: pointer to register value to be filled.
29214ea315bSMartina Krasteva  *
29314ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
29414ea315bSMartina Krasteva  */
29514ea315bSMartina Krasteva static int ov9282_read_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 *val)
29614ea315bSMartina Krasteva {
29714ea315bSMartina Krasteva 	struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd);
29814ea315bSMartina Krasteva 	struct i2c_msg msgs[2] = {0};
29914ea315bSMartina Krasteva 	u8 addr_buf[2] = {0};
30014ea315bSMartina Krasteva 	u8 data_buf[4] = {0};
30114ea315bSMartina Krasteva 	int ret;
30214ea315bSMartina Krasteva 
30314ea315bSMartina Krasteva 	if (WARN_ON(len > 4))
30414ea315bSMartina Krasteva 		return -EINVAL;
30514ea315bSMartina Krasteva 
30614ea315bSMartina Krasteva 	put_unaligned_be16(reg, addr_buf);
30714ea315bSMartina Krasteva 
30814ea315bSMartina Krasteva 	/* Write register address */
30914ea315bSMartina Krasteva 	msgs[0].addr = client->addr;
31014ea315bSMartina Krasteva 	msgs[0].flags = 0;
31114ea315bSMartina Krasteva 	msgs[0].len = ARRAY_SIZE(addr_buf);
31214ea315bSMartina Krasteva 	msgs[0].buf = addr_buf;
31314ea315bSMartina Krasteva 
31414ea315bSMartina Krasteva 	/* Read data from register */
31514ea315bSMartina Krasteva 	msgs[1].addr = client->addr;
31614ea315bSMartina Krasteva 	msgs[1].flags = I2C_M_RD;
31714ea315bSMartina Krasteva 	msgs[1].len = len;
31814ea315bSMartina Krasteva 	msgs[1].buf = &data_buf[4 - len];
31914ea315bSMartina Krasteva 
32014ea315bSMartina Krasteva 	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
32114ea315bSMartina Krasteva 	if (ret != ARRAY_SIZE(msgs))
32214ea315bSMartina Krasteva 		return -EIO;
32314ea315bSMartina Krasteva 
32414ea315bSMartina Krasteva 	*val = get_unaligned_be32(data_buf);
32514ea315bSMartina Krasteva 
32614ea315bSMartina Krasteva 	return 0;
32714ea315bSMartina Krasteva }
32814ea315bSMartina Krasteva 
32914ea315bSMartina Krasteva /**
33014ea315bSMartina Krasteva  * ov9282_write_reg() - Write register
33114ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
33214ea315bSMartina Krasteva  * @reg: register address
33314ea315bSMartina Krasteva  * @len: length of bytes. Max supported bytes is 4
33414ea315bSMartina Krasteva  * @val: register value
33514ea315bSMartina Krasteva  *
33614ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
33714ea315bSMartina Krasteva  */
33814ea315bSMartina Krasteva static int ov9282_write_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 val)
33914ea315bSMartina Krasteva {
34014ea315bSMartina Krasteva 	struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd);
34114ea315bSMartina Krasteva 	u8 buf[6] = {0};
34214ea315bSMartina Krasteva 
34314ea315bSMartina Krasteva 	if (WARN_ON(len > 4))
34414ea315bSMartina Krasteva 		return -EINVAL;
34514ea315bSMartina Krasteva 
34614ea315bSMartina Krasteva 	put_unaligned_be16(reg, buf);
34714ea315bSMartina Krasteva 	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
34814ea315bSMartina Krasteva 	if (i2c_master_send(client, buf, len + 2) != len + 2)
34914ea315bSMartina Krasteva 		return -EIO;
35014ea315bSMartina Krasteva 
35114ea315bSMartina Krasteva 	return 0;
35214ea315bSMartina Krasteva }
35314ea315bSMartina Krasteva 
35414ea315bSMartina Krasteva /**
35514ea315bSMartina Krasteva  * ov9282_write_regs() - Write a list of registers
35614ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
35714ea315bSMartina Krasteva  * @regs: list of registers to be written
35814ea315bSMartina Krasteva  * @len: length of registers array
35914ea315bSMartina Krasteva  *
36014ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
36114ea315bSMartina Krasteva  */
36214ea315bSMartina Krasteva static int ov9282_write_regs(struct ov9282 *ov9282,
36314ea315bSMartina Krasteva 			     const struct ov9282_reg *regs, u32 len)
36414ea315bSMartina Krasteva {
36514ea315bSMartina Krasteva 	unsigned int i;
36614ea315bSMartina Krasteva 	int ret;
36714ea315bSMartina Krasteva 
36814ea315bSMartina Krasteva 	for (i = 0; i < len; i++) {
36914ea315bSMartina Krasteva 		ret = ov9282_write_reg(ov9282, regs[i].address, 1, regs[i].val);
37014ea315bSMartina Krasteva 		if (ret)
37114ea315bSMartina Krasteva 			return ret;
37214ea315bSMartina Krasteva 	}
37314ea315bSMartina Krasteva 
37414ea315bSMartina Krasteva 	return 0;
37514ea315bSMartina Krasteva }
37614ea315bSMartina Krasteva 
37714ea315bSMartina Krasteva /**
37814ea315bSMartina Krasteva  * ov9282_update_controls() - Update control ranges based on streaming mode
37914ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
38014ea315bSMartina Krasteva  * @mode: pointer to ov9282_mode sensor mode
38114ea315bSMartina Krasteva  *
38214ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
38314ea315bSMartina Krasteva  */
38414ea315bSMartina Krasteva static int ov9282_update_controls(struct ov9282 *ov9282,
38514ea315bSMartina Krasteva 				  const struct ov9282_mode *mode)
38614ea315bSMartina Krasteva {
38714ea315bSMartina Krasteva 	int ret;
38814ea315bSMartina Krasteva 
38914ea315bSMartina Krasteva 	ret = __v4l2_ctrl_s_ctrl(ov9282->link_freq_ctrl, mode->link_freq_idx);
39014ea315bSMartina Krasteva 	if (ret)
39114ea315bSMartina Krasteva 		return ret;
39214ea315bSMartina Krasteva 
39314ea315bSMartina Krasteva 	ret = __v4l2_ctrl_s_ctrl(ov9282->hblank_ctrl, mode->hblank);
39414ea315bSMartina Krasteva 	if (ret)
39514ea315bSMartina Krasteva 		return ret;
39614ea315bSMartina Krasteva 
39714ea315bSMartina Krasteva 	return __v4l2_ctrl_modify_range(ov9282->vblank_ctrl, mode->vblank_min,
39814ea315bSMartina Krasteva 					mode->vblank_max, 1, mode->vblank);
39914ea315bSMartina Krasteva }
40014ea315bSMartina Krasteva 
40114ea315bSMartina Krasteva /**
40214ea315bSMartina Krasteva  * ov9282_update_exp_gain() - Set updated exposure and gain
40314ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
40414ea315bSMartina Krasteva  * @exposure: updated exposure value
40514ea315bSMartina Krasteva  * @gain: updated analog gain value
40614ea315bSMartina Krasteva  *
40714ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
40814ea315bSMartina Krasteva  */
40914ea315bSMartina Krasteva static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain)
41014ea315bSMartina Krasteva {
41114ea315bSMartina Krasteva 	u32 lpfr;
41214ea315bSMartina Krasteva 	int ret;
41314ea315bSMartina Krasteva 
41414ea315bSMartina Krasteva 	lpfr = ov9282->vblank + ov9282->cur_mode->height;
41514ea315bSMartina Krasteva 
41614ea315bSMartina Krasteva 	dev_dbg(ov9282->dev, "Set exp %u, analog gain %u, lpfr %u",
41714ea315bSMartina Krasteva 		exposure, gain, lpfr);
41814ea315bSMartina Krasteva 
41914ea315bSMartina Krasteva 	ret = ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 1);
42014ea315bSMartina Krasteva 	if (ret)
42114ea315bSMartina Krasteva 		return ret;
42214ea315bSMartina Krasteva 
42314ea315bSMartina Krasteva 	ret = ov9282_write_reg(ov9282, OV9282_REG_LPFR, 2, lpfr);
42414ea315bSMartina Krasteva 	if (ret)
42514ea315bSMartina Krasteva 		goto error_release_group_hold;
42614ea315bSMartina Krasteva 
42714ea315bSMartina Krasteva 	ret = ov9282_write_reg(ov9282, OV9282_REG_EXPOSURE, 3, exposure << 4);
42814ea315bSMartina Krasteva 	if (ret)
42914ea315bSMartina Krasteva 		goto error_release_group_hold;
43014ea315bSMartina Krasteva 
43114ea315bSMartina Krasteva 	ret = ov9282_write_reg(ov9282, OV9282_REG_AGAIN, 1, gain);
43214ea315bSMartina Krasteva 
43314ea315bSMartina Krasteva error_release_group_hold:
43414ea315bSMartina Krasteva 	ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 0);
43514ea315bSMartina Krasteva 
43614ea315bSMartina Krasteva 	return ret;
43714ea315bSMartina Krasteva }
43814ea315bSMartina Krasteva 
43914ea315bSMartina Krasteva /**
44014ea315bSMartina Krasteva  * ov9282_set_ctrl() - Set subdevice control
44114ea315bSMartina Krasteva  * @ctrl: pointer to v4l2_ctrl structure
44214ea315bSMartina Krasteva  *
44314ea315bSMartina Krasteva  * Supported controls:
44414ea315bSMartina Krasteva  * - V4L2_CID_VBLANK
44514ea315bSMartina Krasteva  * - cluster controls:
44614ea315bSMartina Krasteva  *   - V4L2_CID_ANALOGUE_GAIN
44714ea315bSMartina Krasteva  *   - V4L2_CID_EXPOSURE
44814ea315bSMartina Krasteva  *
44914ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
45014ea315bSMartina Krasteva  */
45114ea315bSMartina Krasteva static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
45214ea315bSMartina Krasteva {
45314ea315bSMartina Krasteva 	struct ov9282 *ov9282 =
45414ea315bSMartina Krasteva 		container_of(ctrl->handler, struct ov9282, ctrl_handler);
45514ea315bSMartina Krasteva 	u32 analog_gain;
45614ea315bSMartina Krasteva 	u32 exposure;
45714ea315bSMartina Krasteva 	int ret;
45814ea315bSMartina Krasteva 
45914ea315bSMartina Krasteva 	switch (ctrl->id) {
46014ea315bSMartina Krasteva 	case V4L2_CID_VBLANK:
46114ea315bSMartina Krasteva 		ov9282->vblank = ov9282->vblank_ctrl->val;
46214ea315bSMartina Krasteva 
46314ea315bSMartina Krasteva 		dev_dbg(ov9282->dev, "Received vblank %u, new lpfr %u",
46414ea315bSMartina Krasteva 			ov9282->vblank,
46514ea315bSMartina Krasteva 			ov9282->vblank + ov9282->cur_mode->height);
46614ea315bSMartina Krasteva 
46714ea315bSMartina Krasteva 		ret = __v4l2_ctrl_modify_range(ov9282->exp_ctrl,
46814ea315bSMartina Krasteva 					       OV9282_EXPOSURE_MIN,
46914ea315bSMartina Krasteva 					       ov9282->vblank +
47014ea315bSMartina Krasteva 					       ov9282->cur_mode->height -
47114ea315bSMartina Krasteva 					       OV9282_EXPOSURE_OFFSET,
47214ea315bSMartina Krasteva 					       1, OV9282_EXPOSURE_DEFAULT);
47314ea315bSMartina Krasteva 		break;
47414ea315bSMartina Krasteva 	case V4L2_CID_EXPOSURE:
47514ea315bSMartina Krasteva 		/* Set controls only if sensor is in power on state */
47614ea315bSMartina Krasteva 		if (!pm_runtime_get_if_in_use(ov9282->dev))
47714ea315bSMartina Krasteva 			return 0;
47814ea315bSMartina Krasteva 
47914ea315bSMartina Krasteva 		exposure = ctrl->val;
48014ea315bSMartina Krasteva 		analog_gain = ov9282->again_ctrl->val;
48114ea315bSMartina Krasteva 
48214ea315bSMartina Krasteva 		dev_dbg(ov9282->dev, "Received exp %u, analog gain %u",
48314ea315bSMartina Krasteva 			exposure, analog_gain);
48414ea315bSMartina Krasteva 
48514ea315bSMartina Krasteva 		ret = ov9282_update_exp_gain(ov9282, exposure, analog_gain);
48614ea315bSMartina Krasteva 
48714ea315bSMartina Krasteva 		pm_runtime_put(ov9282->dev);
48814ea315bSMartina Krasteva 
48914ea315bSMartina Krasteva 		break;
49014ea315bSMartina Krasteva 	default:
49114ea315bSMartina Krasteva 		dev_err(ov9282->dev, "Invalid control %d", ctrl->id);
49214ea315bSMartina Krasteva 		ret = -EINVAL;
49314ea315bSMartina Krasteva 	}
49414ea315bSMartina Krasteva 
49514ea315bSMartina Krasteva 	return ret;
49614ea315bSMartina Krasteva }
49714ea315bSMartina Krasteva 
49814ea315bSMartina Krasteva /* V4l2 subdevice control ops*/
49914ea315bSMartina Krasteva static const struct v4l2_ctrl_ops ov9282_ctrl_ops = {
50014ea315bSMartina Krasteva 	.s_ctrl = ov9282_set_ctrl,
50114ea315bSMartina Krasteva };
50214ea315bSMartina Krasteva 
50314ea315bSMartina Krasteva /**
50414ea315bSMartina Krasteva  * ov9282_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes
50514ea315bSMartina Krasteva  * @sd: pointer to ov9282 V4L2 sub-device structure
50614ea315bSMartina Krasteva  * @sd_state: V4L2 sub-device configuration
50714ea315bSMartina Krasteva  * @code: V4L2 sub-device code enumeration need to be filled
50814ea315bSMartina Krasteva  *
50914ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
51014ea315bSMartina Krasteva  */
51114ea315bSMartina Krasteva static int ov9282_enum_mbus_code(struct v4l2_subdev *sd,
51214ea315bSMartina Krasteva 				 struct v4l2_subdev_state *sd_state,
51314ea315bSMartina Krasteva 				 struct v4l2_subdev_mbus_code_enum *code)
51414ea315bSMartina Krasteva {
51514ea315bSMartina Krasteva 	if (code->index > 0)
51614ea315bSMartina Krasteva 		return -EINVAL;
51714ea315bSMartina Krasteva 
518bf3c4a5bSDave Stevenson 	code->code = MEDIA_BUS_FMT_Y10_1X10;
51914ea315bSMartina Krasteva 
52014ea315bSMartina Krasteva 	return 0;
52114ea315bSMartina Krasteva }
52214ea315bSMartina Krasteva 
52314ea315bSMartina Krasteva /**
52414ea315bSMartina Krasteva  * ov9282_enum_frame_size() - Enumerate V4L2 sub-device frame sizes
52514ea315bSMartina Krasteva  * @sd: pointer to ov9282 V4L2 sub-device structure
52614ea315bSMartina Krasteva  * @sd_state: V4L2 sub-device configuration
52714ea315bSMartina Krasteva  * @fsize: V4L2 sub-device size enumeration need to be filled
52814ea315bSMartina Krasteva  *
52914ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
53014ea315bSMartina Krasteva  */
53114ea315bSMartina Krasteva static int ov9282_enum_frame_size(struct v4l2_subdev *sd,
53214ea315bSMartina Krasteva 				  struct v4l2_subdev_state *sd_state,
53314ea315bSMartina Krasteva 				  struct v4l2_subdev_frame_size_enum *fsize)
53414ea315bSMartina Krasteva {
535*995809ceSDave Stevenson 	if (fsize->index >= ARRAY_SIZE(supported_modes))
53614ea315bSMartina Krasteva 		return -EINVAL;
53714ea315bSMartina Krasteva 
538bf3c4a5bSDave Stevenson 	if (fsize->code != MEDIA_BUS_FMT_Y10_1X10)
53914ea315bSMartina Krasteva 		return -EINVAL;
54014ea315bSMartina Krasteva 
541*995809ceSDave Stevenson 	fsize->min_width = supported_modes[fsize->index].width;
54214ea315bSMartina Krasteva 	fsize->max_width = fsize->min_width;
543*995809ceSDave Stevenson 	fsize->min_height = supported_modes[fsize->index].height;
54414ea315bSMartina Krasteva 	fsize->max_height = fsize->min_height;
54514ea315bSMartina Krasteva 
54614ea315bSMartina Krasteva 	return 0;
54714ea315bSMartina Krasteva }
54814ea315bSMartina Krasteva 
54914ea315bSMartina Krasteva /**
55014ea315bSMartina Krasteva  * ov9282_fill_pad_format() - Fill subdevice pad format
55114ea315bSMartina Krasteva  *                            from selected sensor mode
55214ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
55314ea315bSMartina Krasteva  * @mode: pointer to ov9282_mode sensor mode
55414ea315bSMartina Krasteva  * @fmt: V4L2 sub-device format need to be filled
55514ea315bSMartina Krasteva  */
55614ea315bSMartina Krasteva static void ov9282_fill_pad_format(struct ov9282 *ov9282,
55714ea315bSMartina Krasteva 				   const struct ov9282_mode *mode,
55814ea315bSMartina Krasteva 				   struct v4l2_subdev_format *fmt)
55914ea315bSMartina Krasteva {
56014ea315bSMartina Krasteva 	fmt->format.width = mode->width;
56114ea315bSMartina Krasteva 	fmt->format.height = mode->height;
562bf3c4a5bSDave Stevenson 	fmt->format.code = MEDIA_BUS_FMT_Y10_1X10;
56314ea315bSMartina Krasteva 	fmt->format.field = V4L2_FIELD_NONE;
56414ea315bSMartina Krasteva 	fmt->format.colorspace = V4L2_COLORSPACE_RAW;
56514ea315bSMartina Krasteva 	fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
56614ea315bSMartina Krasteva 	fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT;
56714ea315bSMartina Krasteva 	fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
56814ea315bSMartina Krasteva }
56914ea315bSMartina Krasteva 
57014ea315bSMartina Krasteva /**
57114ea315bSMartina Krasteva  * ov9282_get_pad_format() - Get subdevice pad format
57214ea315bSMartina Krasteva  * @sd: pointer to ov9282 V4L2 sub-device structure
57314ea315bSMartina Krasteva  * @sd_state: V4L2 sub-device configuration
57414ea315bSMartina Krasteva  * @fmt: V4L2 sub-device format need to be set
57514ea315bSMartina Krasteva  *
57614ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
57714ea315bSMartina Krasteva  */
57814ea315bSMartina Krasteva static int ov9282_get_pad_format(struct v4l2_subdev *sd,
57914ea315bSMartina Krasteva 				 struct v4l2_subdev_state *sd_state,
58014ea315bSMartina Krasteva 				 struct v4l2_subdev_format *fmt)
58114ea315bSMartina Krasteva {
58214ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
58314ea315bSMartina Krasteva 
58414ea315bSMartina Krasteva 	mutex_lock(&ov9282->mutex);
58514ea315bSMartina Krasteva 
58614ea315bSMartina Krasteva 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
58714ea315bSMartina Krasteva 		struct v4l2_mbus_framefmt *framefmt;
58814ea315bSMartina Krasteva 
58914ea315bSMartina Krasteva 		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
59014ea315bSMartina Krasteva 		fmt->format = *framefmt;
59114ea315bSMartina Krasteva 	} else {
59214ea315bSMartina Krasteva 		ov9282_fill_pad_format(ov9282, ov9282->cur_mode, fmt);
59314ea315bSMartina Krasteva 	}
59414ea315bSMartina Krasteva 
59514ea315bSMartina Krasteva 	mutex_unlock(&ov9282->mutex);
59614ea315bSMartina Krasteva 
59714ea315bSMartina Krasteva 	return 0;
59814ea315bSMartina Krasteva }
59914ea315bSMartina Krasteva 
60014ea315bSMartina Krasteva /**
60114ea315bSMartina Krasteva  * ov9282_set_pad_format() - Set subdevice pad format
60214ea315bSMartina Krasteva  * @sd: pointer to ov9282 V4L2 sub-device structure
60314ea315bSMartina Krasteva  * @sd_state: V4L2 sub-device configuration
60414ea315bSMartina Krasteva  * @fmt: V4L2 sub-device format need to be set
60514ea315bSMartina Krasteva  *
60614ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
60714ea315bSMartina Krasteva  */
60814ea315bSMartina Krasteva static int ov9282_set_pad_format(struct v4l2_subdev *sd,
60914ea315bSMartina Krasteva 				 struct v4l2_subdev_state *sd_state,
61014ea315bSMartina Krasteva 				 struct v4l2_subdev_format *fmt)
61114ea315bSMartina Krasteva {
61214ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
61314ea315bSMartina Krasteva 	const struct ov9282_mode *mode;
61414ea315bSMartina Krasteva 	int ret = 0;
61514ea315bSMartina Krasteva 
61614ea315bSMartina Krasteva 	mutex_lock(&ov9282->mutex);
61714ea315bSMartina Krasteva 
618*995809ceSDave Stevenson 	mode = v4l2_find_nearest_size(supported_modes,
619*995809ceSDave Stevenson 				      ARRAY_SIZE(supported_modes),
620*995809ceSDave Stevenson 				      width, height,
621*995809ceSDave Stevenson 				      fmt->format.width,
622*995809ceSDave Stevenson 				      fmt->format.height);
62314ea315bSMartina Krasteva 	ov9282_fill_pad_format(ov9282, mode, fmt);
62414ea315bSMartina Krasteva 
62514ea315bSMartina Krasteva 	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
62614ea315bSMartina Krasteva 		struct v4l2_mbus_framefmt *framefmt;
62714ea315bSMartina Krasteva 
62814ea315bSMartina Krasteva 		framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
62914ea315bSMartina Krasteva 		*framefmt = fmt->format;
63014ea315bSMartina Krasteva 	} else {
63114ea315bSMartina Krasteva 		ret = ov9282_update_controls(ov9282, mode);
63214ea315bSMartina Krasteva 		if (!ret)
63314ea315bSMartina Krasteva 			ov9282->cur_mode = mode;
63414ea315bSMartina Krasteva 	}
63514ea315bSMartina Krasteva 
63614ea315bSMartina Krasteva 	mutex_unlock(&ov9282->mutex);
63714ea315bSMartina Krasteva 
63814ea315bSMartina Krasteva 	return ret;
63914ea315bSMartina Krasteva }
64014ea315bSMartina Krasteva 
64114ea315bSMartina Krasteva /**
64214ea315bSMartina Krasteva  * ov9282_init_pad_cfg() - Initialize sub-device pad configuration
64314ea315bSMartina Krasteva  * @sd: pointer to ov9282 V4L2 sub-device structure
64414ea315bSMartina Krasteva  * @sd_state: V4L2 sub-device configuration
64514ea315bSMartina Krasteva  *
64614ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
64714ea315bSMartina Krasteva  */
64814ea315bSMartina Krasteva static int ov9282_init_pad_cfg(struct v4l2_subdev *sd,
64914ea315bSMartina Krasteva 			       struct v4l2_subdev_state *sd_state)
65014ea315bSMartina Krasteva {
65114ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
65214ea315bSMartina Krasteva 	struct v4l2_subdev_format fmt = { 0 };
65314ea315bSMartina Krasteva 
65414ea315bSMartina Krasteva 	fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
655*995809ceSDave Stevenson 	ov9282_fill_pad_format(ov9282, &supported_modes[DEFAULT_MODE], &fmt);
65614ea315bSMartina Krasteva 
65714ea315bSMartina Krasteva 	return ov9282_set_pad_format(sd, sd_state, &fmt);
65814ea315bSMartina Krasteva }
65914ea315bSMartina Krasteva 
66014ea315bSMartina Krasteva /**
66114ea315bSMartina Krasteva  * ov9282_start_streaming() - Start sensor stream
66214ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
66314ea315bSMartina Krasteva  *
66414ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
66514ea315bSMartina Krasteva  */
66614ea315bSMartina Krasteva static int ov9282_start_streaming(struct ov9282 *ov9282)
66714ea315bSMartina Krasteva {
66814ea315bSMartina Krasteva 	const struct ov9282_reg_list *reg_list;
66914ea315bSMartina Krasteva 	int ret;
67014ea315bSMartina Krasteva 
6717195aabfSDave Stevenson 	/* Write common registers */
6727195aabfSDave Stevenson 	ret = ov9282_write_regs(ov9282, common_regs_list.regs,
6737195aabfSDave Stevenson 				common_regs_list.num_of_regs);
6747195aabfSDave Stevenson 	if (ret) {
6757195aabfSDave Stevenson 		dev_err(ov9282->dev, "fail to write common registers");
6767195aabfSDave Stevenson 		return ret;
6777195aabfSDave Stevenson 	}
6787195aabfSDave Stevenson 
67914ea315bSMartina Krasteva 	/* Write sensor mode registers */
68014ea315bSMartina Krasteva 	reg_list = &ov9282->cur_mode->reg_list;
68114ea315bSMartina Krasteva 	ret = ov9282_write_regs(ov9282, reg_list->regs, reg_list->num_of_regs);
68214ea315bSMartina Krasteva 	if (ret) {
68314ea315bSMartina Krasteva 		dev_err(ov9282->dev, "fail to write initial registers");
68414ea315bSMartina Krasteva 		return ret;
68514ea315bSMartina Krasteva 	}
68614ea315bSMartina Krasteva 
68714ea315bSMartina Krasteva 	/* Setup handler will write actual exposure and gain */
68814ea315bSMartina Krasteva 	ret =  __v4l2_ctrl_handler_setup(ov9282->sd.ctrl_handler);
68914ea315bSMartina Krasteva 	if (ret) {
69014ea315bSMartina Krasteva 		dev_err(ov9282->dev, "fail to setup handler");
69114ea315bSMartina Krasteva 		return ret;
69214ea315bSMartina Krasteva 	}
69314ea315bSMartina Krasteva 
69414ea315bSMartina Krasteva 	/* Start streaming */
69514ea315bSMartina Krasteva 	ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT,
69614ea315bSMartina Krasteva 			       1, OV9282_MODE_STREAMING);
69714ea315bSMartina Krasteva 	if (ret) {
69814ea315bSMartina Krasteva 		dev_err(ov9282->dev, "fail to start streaming");
69914ea315bSMartina Krasteva 		return ret;
70014ea315bSMartina Krasteva 	}
70114ea315bSMartina Krasteva 
70214ea315bSMartina Krasteva 	return 0;
70314ea315bSMartina Krasteva }
70414ea315bSMartina Krasteva 
70514ea315bSMartina Krasteva /**
70614ea315bSMartina Krasteva  * ov9282_stop_streaming() - Stop sensor stream
70714ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
70814ea315bSMartina Krasteva  *
70914ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
71014ea315bSMartina Krasteva  */
71114ea315bSMartina Krasteva static int ov9282_stop_streaming(struct ov9282 *ov9282)
71214ea315bSMartina Krasteva {
71314ea315bSMartina Krasteva 	return ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT,
71414ea315bSMartina Krasteva 				1, OV9282_MODE_STANDBY);
71514ea315bSMartina Krasteva }
71614ea315bSMartina Krasteva 
71714ea315bSMartina Krasteva /**
71814ea315bSMartina Krasteva  * ov9282_set_stream() - Enable sensor streaming
71914ea315bSMartina Krasteva  * @sd: pointer to ov9282 subdevice
72014ea315bSMartina Krasteva  * @enable: set to enable sensor streaming
72114ea315bSMartina Krasteva  *
72214ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
72314ea315bSMartina Krasteva  */
72414ea315bSMartina Krasteva static int ov9282_set_stream(struct v4l2_subdev *sd, int enable)
72514ea315bSMartina Krasteva {
72614ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
72714ea315bSMartina Krasteva 	int ret;
72814ea315bSMartina Krasteva 
72914ea315bSMartina Krasteva 	mutex_lock(&ov9282->mutex);
73014ea315bSMartina Krasteva 
73114ea315bSMartina Krasteva 	if (ov9282->streaming == enable) {
73214ea315bSMartina Krasteva 		mutex_unlock(&ov9282->mutex);
73314ea315bSMartina Krasteva 		return 0;
73414ea315bSMartina Krasteva 	}
73514ea315bSMartina Krasteva 
73614ea315bSMartina Krasteva 	if (enable) {
73714ea315bSMartina Krasteva 		ret = pm_runtime_resume_and_get(ov9282->dev);
73814ea315bSMartina Krasteva 		if (ret)
73914ea315bSMartina Krasteva 			goto error_unlock;
74014ea315bSMartina Krasteva 
74114ea315bSMartina Krasteva 		ret = ov9282_start_streaming(ov9282);
74214ea315bSMartina Krasteva 		if (ret)
74314ea315bSMartina Krasteva 			goto error_power_off;
74414ea315bSMartina Krasteva 	} else {
74514ea315bSMartina Krasteva 		ov9282_stop_streaming(ov9282);
74614ea315bSMartina Krasteva 		pm_runtime_put(ov9282->dev);
74714ea315bSMartina Krasteva 	}
74814ea315bSMartina Krasteva 
74914ea315bSMartina Krasteva 	ov9282->streaming = enable;
75014ea315bSMartina Krasteva 
75114ea315bSMartina Krasteva 	mutex_unlock(&ov9282->mutex);
75214ea315bSMartina Krasteva 
75314ea315bSMartina Krasteva 	return 0;
75414ea315bSMartina Krasteva 
75514ea315bSMartina Krasteva error_power_off:
75614ea315bSMartina Krasteva 	pm_runtime_put(ov9282->dev);
75714ea315bSMartina Krasteva error_unlock:
75814ea315bSMartina Krasteva 	mutex_unlock(&ov9282->mutex);
75914ea315bSMartina Krasteva 
76014ea315bSMartina Krasteva 	return ret;
76114ea315bSMartina Krasteva }
76214ea315bSMartina Krasteva 
76314ea315bSMartina Krasteva /**
76414ea315bSMartina Krasteva  * ov9282_detect() - Detect ov9282 sensor
76514ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
76614ea315bSMartina Krasteva  *
76714ea315bSMartina Krasteva  * Return: 0 if successful, -EIO if sensor id does not match
76814ea315bSMartina Krasteva  */
76914ea315bSMartina Krasteva static int ov9282_detect(struct ov9282 *ov9282)
77014ea315bSMartina Krasteva {
77114ea315bSMartina Krasteva 	int ret;
77214ea315bSMartina Krasteva 	u32 val;
77314ea315bSMartina Krasteva 
77414ea315bSMartina Krasteva 	ret = ov9282_read_reg(ov9282, OV9282_REG_ID, 2, &val);
77514ea315bSMartina Krasteva 	if (ret)
77614ea315bSMartina Krasteva 		return ret;
77714ea315bSMartina Krasteva 
77814ea315bSMartina Krasteva 	if (val != OV9282_ID) {
77914ea315bSMartina Krasteva 		dev_err(ov9282->dev, "chip id mismatch: %x!=%x",
78014ea315bSMartina Krasteva 			OV9282_ID, val);
78114ea315bSMartina Krasteva 		return -ENXIO;
78214ea315bSMartina Krasteva 	}
78314ea315bSMartina Krasteva 
78414ea315bSMartina Krasteva 	return 0;
78514ea315bSMartina Krasteva }
78614ea315bSMartina Krasteva 
78714ea315bSMartina Krasteva /**
78814ea315bSMartina Krasteva  * ov9282_parse_hw_config() - Parse HW configuration and check if supported
78914ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
79014ea315bSMartina Krasteva  *
79114ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
79214ea315bSMartina Krasteva  */
79314ea315bSMartina Krasteva static int ov9282_parse_hw_config(struct ov9282 *ov9282)
79414ea315bSMartina Krasteva {
79514ea315bSMartina Krasteva 	struct fwnode_handle *fwnode = dev_fwnode(ov9282->dev);
79614ea315bSMartina Krasteva 	struct v4l2_fwnode_endpoint bus_cfg = {
79714ea315bSMartina Krasteva 		.bus_type = V4L2_MBUS_CSI2_DPHY
79814ea315bSMartina Krasteva 	};
79914ea315bSMartina Krasteva 	struct fwnode_handle *ep;
80014ea315bSMartina Krasteva 	unsigned long rate;
80114ea315bSMartina Krasteva 	unsigned int i;
80214ea315bSMartina Krasteva 	int ret;
80314ea315bSMartina Krasteva 
80414ea315bSMartina Krasteva 	if (!fwnode)
80514ea315bSMartina Krasteva 		return -ENXIO;
80614ea315bSMartina Krasteva 
80714ea315bSMartina Krasteva 	/* Request optional reset pin */
80814ea315bSMartina Krasteva 	ov9282->reset_gpio = devm_gpiod_get_optional(ov9282->dev, "reset",
80914ea315bSMartina Krasteva 						     GPIOD_OUT_LOW);
81014ea315bSMartina Krasteva 	if (IS_ERR(ov9282->reset_gpio)) {
81114ea315bSMartina Krasteva 		dev_err(ov9282->dev, "failed to get reset gpio %ld",
81214ea315bSMartina Krasteva 			PTR_ERR(ov9282->reset_gpio));
81314ea315bSMartina Krasteva 		return PTR_ERR(ov9282->reset_gpio);
81414ea315bSMartina Krasteva 	}
81514ea315bSMartina Krasteva 
81614ea315bSMartina Krasteva 	/* Get sensor input clock */
81714ea315bSMartina Krasteva 	ov9282->inclk = devm_clk_get(ov9282->dev, NULL);
81814ea315bSMartina Krasteva 	if (IS_ERR(ov9282->inclk)) {
81914ea315bSMartina Krasteva 		dev_err(ov9282->dev, "could not get inclk");
82014ea315bSMartina Krasteva 		return PTR_ERR(ov9282->inclk);
82114ea315bSMartina Krasteva 	}
82214ea315bSMartina Krasteva 
82314ea315bSMartina Krasteva 	rate = clk_get_rate(ov9282->inclk);
82414ea315bSMartina Krasteva 	if (rate != OV9282_INCLK_RATE) {
82514ea315bSMartina Krasteva 		dev_err(ov9282->dev, "inclk frequency mismatch");
82614ea315bSMartina Krasteva 		return -EINVAL;
82714ea315bSMartina Krasteva 	}
82814ea315bSMartina Krasteva 
82914ea315bSMartina Krasteva 	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
83014ea315bSMartina Krasteva 	if (!ep)
83114ea315bSMartina Krasteva 		return -ENXIO;
83214ea315bSMartina Krasteva 
83314ea315bSMartina Krasteva 	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
83414ea315bSMartina Krasteva 	fwnode_handle_put(ep);
83514ea315bSMartina Krasteva 	if (ret)
83614ea315bSMartina Krasteva 		return ret;
83714ea315bSMartina Krasteva 
83814ea315bSMartina Krasteva 	if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV9282_NUM_DATA_LANES) {
83914ea315bSMartina Krasteva 		dev_err(ov9282->dev,
84014ea315bSMartina Krasteva 			"number of CSI2 data lanes %d is not supported",
84114ea315bSMartina Krasteva 			bus_cfg.bus.mipi_csi2.num_data_lanes);
84214ea315bSMartina Krasteva 		ret = -EINVAL;
84314ea315bSMartina Krasteva 		goto done_endpoint_free;
84414ea315bSMartina Krasteva 	}
84514ea315bSMartina Krasteva 
84614ea315bSMartina Krasteva 	if (!bus_cfg.nr_of_link_frequencies) {
84714ea315bSMartina Krasteva 		dev_err(ov9282->dev, "no link frequencies defined");
84814ea315bSMartina Krasteva 		ret = -EINVAL;
84914ea315bSMartina Krasteva 		goto done_endpoint_free;
85014ea315bSMartina Krasteva 	}
85114ea315bSMartina Krasteva 
85214ea315bSMartina Krasteva 	for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
85314ea315bSMartina Krasteva 		if (bus_cfg.link_frequencies[i] == OV9282_LINK_FREQ)
85414ea315bSMartina Krasteva 			goto done_endpoint_free;
85514ea315bSMartina Krasteva 
85614ea315bSMartina Krasteva 	ret = -EINVAL;
85714ea315bSMartina Krasteva 
85814ea315bSMartina Krasteva done_endpoint_free:
85914ea315bSMartina Krasteva 	v4l2_fwnode_endpoint_free(&bus_cfg);
86014ea315bSMartina Krasteva 
86114ea315bSMartina Krasteva 	return ret;
86214ea315bSMartina Krasteva }
86314ea315bSMartina Krasteva 
86414ea315bSMartina Krasteva /* V4l2 subdevice ops */
86514ea315bSMartina Krasteva static const struct v4l2_subdev_video_ops ov9282_video_ops = {
86614ea315bSMartina Krasteva 	.s_stream = ov9282_set_stream,
86714ea315bSMartina Krasteva };
86814ea315bSMartina Krasteva 
86914ea315bSMartina Krasteva static const struct v4l2_subdev_pad_ops ov9282_pad_ops = {
87014ea315bSMartina Krasteva 	.init_cfg = ov9282_init_pad_cfg,
87114ea315bSMartina Krasteva 	.enum_mbus_code = ov9282_enum_mbus_code,
87214ea315bSMartina Krasteva 	.enum_frame_size = ov9282_enum_frame_size,
87314ea315bSMartina Krasteva 	.get_fmt = ov9282_get_pad_format,
87414ea315bSMartina Krasteva 	.set_fmt = ov9282_set_pad_format,
87514ea315bSMartina Krasteva };
87614ea315bSMartina Krasteva 
87714ea315bSMartina Krasteva static const struct v4l2_subdev_ops ov9282_subdev_ops = {
87814ea315bSMartina Krasteva 	.video = &ov9282_video_ops,
87914ea315bSMartina Krasteva 	.pad = &ov9282_pad_ops,
88014ea315bSMartina Krasteva };
88114ea315bSMartina Krasteva 
88214ea315bSMartina Krasteva /**
88314ea315bSMartina Krasteva  * ov9282_power_on() - Sensor power on sequence
88414ea315bSMartina Krasteva  * @dev: pointer to i2c device
88514ea315bSMartina Krasteva  *
88614ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
88714ea315bSMartina Krasteva  */
88814ea315bSMartina Krasteva static int ov9282_power_on(struct device *dev)
88914ea315bSMartina Krasteva {
89014ea315bSMartina Krasteva 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
89114ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
89214ea315bSMartina Krasteva 	int ret;
89314ea315bSMartina Krasteva 
89414ea315bSMartina Krasteva 	usleep_range(400, 600);
89514ea315bSMartina Krasteva 
89614ea315bSMartina Krasteva 	gpiod_set_value_cansleep(ov9282->reset_gpio, 1);
89714ea315bSMartina Krasteva 
89814ea315bSMartina Krasteva 	ret = clk_prepare_enable(ov9282->inclk);
89914ea315bSMartina Krasteva 	if (ret) {
90014ea315bSMartina Krasteva 		dev_err(ov9282->dev, "fail to enable inclk");
90114ea315bSMartina Krasteva 		goto error_reset;
90214ea315bSMartina Krasteva 	}
90314ea315bSMartina Krasteva 
90414ea315bSMartina Krasteva 	usleep_range(400, 600);
90514ea315bSMartina Krasteva 
90614ea315bSMartina Krasteva 	return 0;
90714ea315bSMartina Krasteva 
90814ea315bSMartina Krasteva error_reset:
90914ea315bSMartina Krasteva 	gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
91014ea315bSMartina Krasteva 
91114ea315bSMartina Krasteva 	return ret;
91214ea315bSMartina Krasteva }
91314ea315bSMartina Krasteva 
91414ea315bSMartina Krasteva /**
91514ea315bSMartina Krasteva  * ov9282_power_off() - Sensor power off sequence
91614ea315bSMartina Krasteva  * @dev: pointer to i2c device
91714ea315bSMartina Krasteva  *
91814ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
91914ea315bSMartina Krasteva  */
92014ea315bSMartina Krasteva static int ov9282_power_off(struct device *dev)
92114ea315bSMartina Krasteva {
92214ea315bSMartina Krasteva 	struct v4l2_subdev *sd = dev_get_drvdata(dev);
92314ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
92414ea315bSMartina Krasteva 
92514ea315bSMartina Krasteva 	gpiod_set_value_cansleep(ov9282->reset_gpio, 0);
92614ea315bSMartina Krasteva 
92714ea315bSMartina Krasteva 	clk_disable_unprepare(ov9282->inclk);
92814ea315bSMartina Krasteva 
92914ea315bSMartina Krasteva 	return 0;
93014ea315bSMartina Krasteva }
93114ea315bSMartina Krasteva 
93214ea315bSMartina Krasteva /**
93314ea315bSMartina Krasteva  * ov9282_init_controls() - Initialize sensor subdevice controls
93414ea315bSMartina Krasteva  * @ov9282: pointer to ov9282 device
93514ea315bSMartina Krasteva  *
93614ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
93714ea315bSMartina Krasteva  */
93814ea315bSMartina Krasteva static int ov9282_init_controls(struct ov9282 *ov9282)
93914ea315bSMartina Krasteva {
94014ea315bSMartina Krasteva 	struct v4l2_ctrl_handler *ctrl_hdlr = &ov9282->ctrl_handler;
94114ea315bSMartina Krasteva 	const struct ov9282_mode *mode = ov9282->cur_mode;
94214ea315bSMartina Krasteva 	u32 lpfr;
94314ea315bSMartina Krasteva 	int ret;
94414ea315bSMartina Krasteva 
94514ea315bSMartina Krasteva 	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6);
94614ea315bSMartina Krasteva 	if (ret)
94714ea315bSMartina Krasteva 		return ret;
94814ea315bSMartina Krasteva 
94914ea315bSMartina Krasteva 	/* Serialize controls with sensor device */
95014ea315bSMartina Krasteva 	ctrl_hdlr->lock = &ov9282->mutex;
95114ea315bSMartina Krasteva 
95214ea315bSMartina Krasteva 	/* Initialize exposure and gain */
95314ea315bSMartina Krasteva 	lpfr = mode->vblank + mode->height;
95414ea315bSMartina Krasteva 	ov9282->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
95514ea315bSMartina Krasteva 					     &ov9282_ctrl_ops,
95614ea315bSMartina Krasteva 					     V4L2_CID_EXPOSURE,
95714ea315bSMartina Krasteva 					     OV9282_EXPOSURE_MIN,
95814ea315bSMartina Krasteva 					     lpfr - OV9282_EXPOSURE_OFFSET,
95914ea315bSMartina Krasteva 					     OV9282_EXPOSURE_STEP,
96014ea315bSMartina Krasteva 					     OV9282_EXPOSURE_DEFAULT);
96114ea315bSMartina Krasteva 
96214ea315bSMartina Krasteva 	ov9282->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
96314ea315bSMartina Krasteva 					       &ov9282_ctrl_ops,
96414ea315bSMartina Krasteva 					       V4L2_CID_ANALOGUE_GAIN,
96514ea315bSMartina Krasteva 					       OV9282_AGAIN_MIN,
96614ea315bSMartina Krasteva 					       OV9282_AGAIN_MAX,
96714ea315bSMartina Krasteva 					       OV9282_AGAIN_STEP,
96814ea315bSMartina Krasteva 					       OV9282_AGAIN_DEFAULT);
96914ea315bSMartina Krasteva 
97014ea315bSMartina Krasteva 	v4l2_ctrl_cluster(2, &ov9282->exp_ctrl);
97114ea315bSMartina Krasteva 
97214ea315bSMartina Krasteva 	ov9282->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
97314ea315bSMartina Krasteva 						&ov9282_ctrl_ops,
97414ea315bSMartina Krasteva 						V4L2_CID_VBLANK,
97514ea315bSMartina Krasteva 						mode->vblank_min,
97614ea315bSMartina Krasteva 						mode->vblank_max,
97714ea315bSMartina Krasteva 						1, mode->vblank);
97814ea315bSMartina Krasteva 
97914ea315bSMartina Krasteva 	/* Read only controls */
980f15b0612SDave Stevenson 	v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops, V4L2_CID_PIXEL_RATE,
981f15b0612SDave Stevenson 			  OV9282_PIXEL_RATE, OV9282_PIXEL_RATE, 1,
982f15b0612SDave Stevenson 			  OV9282_PIXEL_RATE);
98314ea315bSMartina Krasteva 
98414ea315bSMartina Krasteva 	ov9282->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr,
98514ea315bSMartina Krasteva 							&ov9282_ctrl_ops,
98614ea315bSMartina Krasteva 							V4L2_CID_LINK_FREQ,
98714ea315bSMartina Krasteva 							ARRAY_SIZE(link_freq) -
98814ea315bSMartina Krasteva 							1,
98914ea315bSMartina Krasteva 							mode->link_freq_idx,
99014ea315bSMartina Krasteva 							link_freq);
99114ea315bSMartina Krasteva 	if (ov9282->link_freq_ctrl)
99214ea315bSMartina Krasteva 		ov9282->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
99314ea315bSMartina Krasteva 
99414ea315bSMartina Krasteva 	ov9282->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr,
99514ea315bSMartina Krasteva 						&ov9282_ctrl_ops,
99614ea315bSMartina Krasteva 						V4L2_CID_HBLANK,
99714ea315bSMartina Krasteva 						OV9282_REG_MIN,
99814ea315bSMartina Krasteva 						OV9282_REG_MAX,
99914ea315bSMartina Krasteva 						1, mode->hblank);
100014ea315bSMartina Krasteva 	if (ov9282->hblank_ctrl)
100114ea315bSMartina Krasteva 		ov9282->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
100214ea315bSMartina Krasteva 
100314ea315bSMartina Krasteva 	if (ctrl_hdlr->error) {
100414ea315bSMartina Krasteva 		dev_err(ov9282->dev, "control init failed: %d",
100514ea315bSMartina Krasteva 			ctrl_hdlr->error);
100614ea315bSMartina Krasteva 		v4l2_ctrl_handler_free(ctrl_hdlr);
100714ea315bSMartina Krasteva 		return ctrl_hdlr->error;
100814ea315bSMartina Krasteva 	}
100914ea315bSMartina Krasteva 
101014ea315bSMartina Krasteva 	ov9282->sd.ctrl_handler = ctrl_hdlr;
101114ea315bSMartina Krasteva 
101214ea315bSMartina Krasteva 	return 0;
101314ea315bSMartina Krasteva }
101414ea315bSMartina Krasteva 
101514ea315bSMartina Krasteva /**
101614ea315bSMartina Krasteva  * ov9282_probe() - I2C client device binding
101714ea315bSMartina Krasteva  * @client: pointer to i2c client device
101814ea315bSMartina Krasteva  *
101914ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
102014ea315bSMartina Krasteva  */
102114ea315bSMartina Krasteva static int ov9282_probe(struct i2c_client *client)
102214ea315bSMartina Krasteva {
102314ea315bSMartina Krasteva 	struct ov9282 *ov9282;
102414ea315bSMartina Krasteva 	int ret;
102514ea315bSMartina Krasteva 
102614ea315bSMartina Krasteva 	ov9282 = devm_kzalloc(&client->dev, sizeof(*ov9282), GFP_KERNEL);
102714ea315bSMartina Krasteva 	if (!ov9282)
102814ea315bSMartina Krasteva 		return -ENOMEM;
102914ea315bSMartina Krasteva 
103014ea315bSMartina Krasteva 	ov9282->dev = &client->dev;
103114ea315bSMartina Krasteva 
103214ea315bSMartina Krasteva 	/* Initialize subdev */
103314ea315bSMartina Krasteva 	v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops);
103414ea315bSMartina Krasteva 
103514ea315bSMartina Krasteva 	ret = ov9282_parse_hw_config(ov9282);
103614ea315bSMartina Krasteva 	if (ret) {
103714ea315bSMartina Krasteva 		dev_err(ov9282->dev, "HW configuration is not supported");
103814ea315bSMartina Krasteva 		return ret;
103914ea315bSMartina Krasteva 	}
104014ea315bSMartina Krasteva 
104114ea315bSMartina Krasteva 	mutex_init(&ov9282->mutex);
104214ea315bSMartina Krasteva 
104314ea315bSMartina Krasteva 	ret = ov9282_power_on(ov9282->dev);
104414ea315bSMartina Krasteva 	if (ret) {
104514ea315bSMartina Krasteva 		dev_err(ov9282->dev, "failed to power-on the sensor");
104614ea315bSMartina Krasteva 		goto error_mutex_destroy;
104714ea315bSMartina Krasteva 	}
104814ea315bSMartina Krasteva 
104914ea315bSMartina Krasteva 	/* Check module identity */
105014ea315bSMartina Krasteva 	ret = ov9282_detect(ov9282);
105114ea315bSMartina Krasteva 	if (ret) {
105214ea315bSMartina Krasteva 		dev_err(ov9282->dev, "failed to find sensor: %d", ret);
105314ea315bSMartina Krasteva 		goto error_power_off;
105414ea315bSMartina Krasteva 	}
105514ea315bSMartina Krasteva 
1056*995809ceSDave Stevenson 	/* Set default mode to first mode */
1057*995809ceSDave Stevenson 	ov9282->cur_mode = &supported_modes[DEFAULT_MODE];
105814ea315bSMartina Krasteva 	ov9282->vblank = ov9282->cur_mode->vblank;
105914ea315bSMartina Krasteva 
106014ea315bSMartina Krasteva 	ret = ov9282_init_controls(ov9282);
106114ea315bSMartina Krasteva 	if (ret) {
106214ea315bSMartina Krasteva 		dev_err(ov9282->dev, "failed to init controls: %d", ret);
106314ea315bSMartina Krasteva 		goto error_power_off;
106414ea315bSMartina Krasteva 	}
106514ea315bSMartina Krasteva 
106614ea315bSMartina Krasteva 	/* Initialize subdev */
106714ea315bSMartina Krasteva 	ov9282->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
106814ea315bSMartina Krasteva 	ov9282->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
106914ea315bSMartina Krasteva 
107014ea315bSMartina Krasteva 	/* Initialize source pad */
107114ea315bSMartina Krasteva 	ov9282->pad.flags = MEDIA_PAD_FL_SOURCE;
107214ea315bSMartina Krasteva 	ret = media_entity_pads_init(&ov9282->sd.entity, 1, &ov9282->pad);
107314ea315bSMartina Krasteva 	if (ret) {
107414ea315bSMartina Krasteva 		dev_err(ov9282->dev, "failed to init entity pads: %d", ret);
107514ea315bSMartina Krasteva 		goto error_handler_free;
107614ea315bSMartina Krasteva 	}
107714ea315bSMartina Krasteva 
107814ea315bSMartina Krasteva 	ret = v4l2_async_register_subdev_sensor(&ov9282->sd);
107914ea315bSMartina Krasteva 	if (ret < 0) {
108014ea315bSMartina Krasteva 		dev_err(ov9282->dev,
108114ea315bSMartina Krasteva 			"failed to register async subdev: %d", ret);
108214ea315bSMartina Krasteva 		goto error_media_entity;
108314ea315bSMartina Krasteva 	}
108414ea315bSMartina Krasteva 
108514ea315bSMartina Krasteva 	pm_runtime_set_active(ov9282->dev);
108614ea315bSMartina Krasteva 	pm_runtime_enable(ov9282->dev);
108714ea315bSMartina Krasteva 	pm_runtime_idle(ov9282->dev);
108814ea315bSMartina Krasteva 
108914ea315bSMartina Krasteva 	return 0;
109014ea315bSMartina Krasteva 
109114ea315bSMartina Krasteva error_media_entity:
109214ea315bSMartina Krasteva 	media_entity_cleanup(&ov9282->sd.entity);
109314ea315bSMartina Krasteva error_handler_free:
109414ea315bSMartina Krasteva 	v4l2_ctrl_handler_free(ov9282->sd.ctrl_handler);
109514ea315bSMartina Krasteva error_power_off:
109614ea315bSMartina Krasteva 	ov9282_power_off(ov9282->dev);
109714ea315bSMartina Krasteva error_mutex_destroy:
109814ea315bSMartina Krasteva 	mutex_destroy(&ov9282->mutex);
109914ea315bSMartina Krasteva 
110014ea315bSMartina Krasteva 	return ret;
110114ea315bSMartina Krasteva }
110214ea315bSMartina Krasteva 
110314ea315bSMartina Krasteva /**
110414ea315bSMartina Krasteva  * ov9282_remove() - I2C client device unbinding
110514ea315bSMartina Krasteva  * @client: pointer to I2C client device
110614ea315bSMartina Krasteva  *
110714ea315bSMartina Krasteva  * Return: 0 if successful, error code otherwise.
110814ea315bSMartina Krasteva  */
1109ed5c2f5fSUwe Kleine-König static void ov9282_remove(struct i2c_client *client)
111014ea315bSMartina Krasteva {
111114ea315bSMartina Krasteva 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
111214ea315bSMartina Krasteva 	struct ov9282 *ov9282 = to_ov9282(sd);
111314ea315bSMartina Krasteva 
111414ea315bSMartina Krasteva 	v4l2_async_unregister_subdev(sd);
111514ea315bSMartina Krasteva 	media_entity_cleanup(&sd->entity);
111614ea315bSMartina Krasteva 	v4l2_ctrl_handler_free(sd->ctrl_handler);
111714ea315bSMartina Krasteva 
111814ea315bSMartina Krasteva 	pm_runtime_disable(&client->dev);
111914ea315bSMartina Krasteva 	if (!pm_runtime_status_suspended(&client->dev))
112014ea315bSMartina Krasteva 		ov9282_power_off(&client->dev);
112114ea315bSMartina Krasteva 	pm_runtime_set_suspended(&client->dev);
112214ea315bSMartina Krasteva 
112314ea315bSMartina Krasteva 	mutex_destroy(&ov9282->mutex);
112414ea315bSMartina Krasteva }
112514ea315bSMartina Krasteva 
112614ea315bSMartina Krasteva static const struct dev_pm_ops ov9282_pm_ops = {
112714ea315bSMartina Krasteva 	SET_RUNTIME_PM_OPS(ov9282_power_off, ov9282_power_on, NULL)
112814ea315bSMartina Krasteva };
112914ea315bSMartina Krasteva 
113014ea315bSMartina Krasteva static const struct of_device_id ov9282_of_match[] = {
113114ea315bSMartina Krasteva 	{ .compatible = "ovti,ov9282" },
113214ea315bSMartina Krasteva 	{ }
113314ea315bSMartina Krasteva };
113414ea315bSMartina Krasteva 
113514ea315bSMartina Krasteva MODULE_DEVICE_TABLE(of, ov9282_of_match);
113614ea315bSMartina Krasteva 
113714ea315bSMartina Krasteva static struct i2c_driver ov9282_driver = {
113814ea315bSMartina Krasteva 	.probe_new = ov9282_probe,
113914ea315bSMartina Krasteva 	.remove = ov9282_remove,
114014ea315bSMartina Krasteva 	.driver = {
114114ea315bSMartina Krasteva 		.name = "ov9282",
114214ea315bSMartina Krasteva 		.pm = &ov9282_pm_ops,
114314ea315bSMartina Krasteva 		.of_match_table = ov9282_of_match,
114414ea315bSMartina Krasteva 	},
114514ea315bSMartina Krasteva };
114614ea315bSMartina Krasteva 
114714ea315bSMartina Krasteva module_i2c_driver(ov9282_driver);
114814ea315bSMartina Krasteva 
114914ea315bSMartina Krasteva MODULE_DESCRIPTION("OmniVision ov9282 sensor driver");
115014ea315bSMartina Krasteva MODULE_LICENSE("GPL");
1151