xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision e74ef55b)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
219a81c14SSteve Longerbeam /*
319a81c14SSteve Longerbeam  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
419a81c14SSteve Longerbeam  * Copyright (C) 2014-2017 Mentor Graphics Inc.
519a81c14SSteve Longerbeam  */
619a81c14SSteve Longerbeam 
719a81c14SSteve Longerbeam #include <linux/clk.h>
819a81c14SSteve Longerbeam #include <linux/clk-provider.h>
919a81c14SSteve Longerbeam #include <linux/clkdev.h>
1019a81c14SSteve Longerbeam #include <linux/ctype.h>
1119a81c14SSteve Longerbeam #include <linux/delay.h>
1219a81c14SSteve Longerbeam #include <linux/device.h>
1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h>
1419a81c14SSteve Longerbeam #include <linux/i2c.h>
1519a81c14SSteve Longerbeam #include <linux/init.h>
1619a81c14SSteve Longerbeam #include <linux/module.h>
1719a81c14SSteve Longerbeam #include <linux/of_device.h>
1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
1919a81c14SSteve Longerbeam #include <linux/slab.h>
2019a81c14SSteve Longerbeam #include <linux/types.h>
2119a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-device.h>
242d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2719a81c14SSteve Longerbeam 
2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3119a81c14SSteve Longerbeam 
3219a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
3319a81c14SSteve Longerbeam 
343c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
353c28588fSJacopo Mondi 
36d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
37d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
38f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
393b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
403b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
4119a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
42f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
43f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
44f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
4519a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
46f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
4719a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
4819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
4919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
5019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
5119a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
52f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
5319a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
5419a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
5519a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
5619a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
5719a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
5819a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
5919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
6019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
6119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
6219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
6319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
643145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS		0x3800
653145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS		0x3802
663145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW		0x3804
673145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH		0x3806
6886633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
6986633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
7019a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
7119a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
723145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS		0x3810
733145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS		0x3812
74ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
7519a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
7619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
7719a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
7819a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
7919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
8019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
8119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
8219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
8319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
8419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
8519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
8619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
8719a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
8819a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
8919a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
9019a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
91e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
927cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
937cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
942b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
954039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
96f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
9719a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
9819a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
996c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
100e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
10119a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
10219a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
10319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
10419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
10519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
10619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
10719a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
10819a81c14SSteve Longerbeam 
10919a81c14SSteve Longerbeam enum ov5640_mode_id {
11032ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
11132ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
11219a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
11319a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
11419a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
11519a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
11619a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
11719a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
11819a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
11919a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
12019a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
12119a81c14SSteve Longerbeam };
12219a81c14SSteve Longerbeam 
12319a81c14SSteve Longerbeam enum ov5640_frame_rate {
12419a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
12519a81c14SSteve Longerbeam 	OV5640_30_FPS,
126e823fb16SMaxime Ripard 	OV5640_60_FPS,
12719a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
12819a81c14SSteve Longerbeam };
12919a81c14SSteve Longerbeam 
13022845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
13122845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
13222845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
13322845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
13422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
13522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
13622845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
13722845bf2SJacopo Mondi };
13822845bf2SJacopo Mondi 
13922845bf2SJacopo Mondi /*
14022845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
14122845bf2SJacopo Mondi  *
14222845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
14322845bf2SJacopo Mondi  * full resolution mode @15 FPS.
14422845bf2SJacopo Mondi  */
14522845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
14622845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
14722845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
14822845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
14922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
15022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
15122845bf2SJacopo Mondi };
15222845bf2SJacopo Mondi 
1537a3b8d4bSJacopo Mondi /*
1547a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1557a3b8d4bSJacopo Mondi  *
1567a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1577a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1587a3b8d4bSJacopo Mondi  *
1597a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1607a3b8d4bSJacopo Mondi  */
1617a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1627a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1637a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1647a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1657a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1667a3b8d4bSJacopo Mondi };
1677a3b8d4bSJacopo Mondi 
1687a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1697a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1707a3b8d4bSJacopo Mondi 
171b7ed3abdSLoic Poulain enum ov5640_format_mux {
172b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
173b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
174b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
175b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
176b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
177b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
178b7ed3abdSLoic Poulain };
179b7ed3abdSLoic Poulain 
1802d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
181e3ee691dSHugues Fruchet 	u32 code;
182e3ee691dSHugues Fruchet 	u32 colorspace;
1832d7671f6SJacopo Mondi 	u8 bpp;
1842d7671f6SJacopo Mondi } ov5640_formats[] = {
1852d7671f6SJacopo Mondi 	{
1862d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1872d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1882d7671f6SJacopo Mondi 		.bpp = 16,
1892d7671f6SJacopo Mondi 	}, {
1902d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
1912d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1922d7671f6SJacopo Mondi 		.bpp = 16,
1932d7671f6SJacopo Mondi 	}, {
1942d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
1952d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1962d7671f6SJacopo Mondi 		.bpp = 16,
1972d7671f6SJacopo Mondi 	}, {
1982d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
1992d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2002d7671f6SJacopo Mondi 		.bpp = 16,
2012d7671f6SJacopo Mondi 	}, {
2022d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
2032d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2042d7671f6SJacopo Mondi 		.bpp = 16,
2052d7671f6SJacopo Mondi 	}, {
2062d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2072d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2082d7671f6SJacopo Mondi 		.bpp = 16,
2092d7671f6SJacopo Mondi 	}, {
2102d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2112d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2122d7671f6SJacopo Mondi 		.bpp = 16,
2132d7671f6SJacopo Mondi 	}, {
2142d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2152d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2162d7671f6SJacopo Mondi 		.bpp = 8,
2172d7671f6SJacopo Mondi 	}, {
2182d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2192d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2202d7671f6SJacopo Mondi 		.bpp = 8
2212d7671f6SJacopo Mondi 	}, {
2222d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2232d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2242d7671f6SJacopo Mondi 		.bpp = 8,
2252d7671f6SJacopo Mondi 	}, {
2262d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2272d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2282d7671f6SJacopo Mondi 		.bpp = 8,
2292d7671f6SJacopo Mondi 	},
230e3ee691dSHugues Fruchet };
231e3ee691dSHugues Fruchet 
2323c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2333c28588fSJacopo Mondi {
2343c28588fSJacopo Mondi 	unsigned int i;
2353c28588fSJacopo Mondi 
2363c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2373c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2383c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2393c28588fSJacopo Mondi 	}
2403c28588fSJacopo Mondi 
2413c28588fSJacopo Mondi 	return 0;
2423c28588fSJacopo Mondi }
2433c28588fSJacopo Mondi 
24419a81c14SSteve Longerbeam /*
24519a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
24619a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
24719a81c14SSteve Longerbeam  */
24819a81c14SSteve Longerbeam static unsigned int virtual_channel;
2498670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
25019a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
25119a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
25219a81c14SSteve Longerbeam 
25319a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
25419a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
25519a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
256e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
25719a81c14SSteve Longerbeam };
25819a81c14SSteve Longerbeam 
25919a81c14SSteve Longerbeam /* regulator supplies */
26019a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
26141d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
26219a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
26324c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
26419a81c14SSteve Longerbeam };
26519a81c14SSteve Longerbeam 
26619a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
26719a81c14SSteve Longerbeam 
26819a81c14SSteve Longerbeam /*
26919a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
27019a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
27119a81c14SSteve Longerbeam  */
27219a81c14SSteve Longerbeam enum ov5640_downsize_mode {
27319a81c14SSteve Longerbeam 	SUBSAMPLING,
27419a81c14SSteve Longerbeam 	SCALING,
27519a81c14SSteve Longerbeam };
27619a81c14SSteve Longerbeam 
27719a81c14SSteve Longerbeam struct reg_value {
27819a81c14SSteve Longerbeam 	u16 reg_addr;
27919a81c14SSteve Longerbeam 	u8 val;
28019a81c14SSteve Longerbeam 	u8 mask;
28119a81c14SSteve Longerbeam 	u32 delay_ms;
28219a81c14SSteve Longerbeam };
28319a81c14SSteve Longerbeam 
28419a81c14SSteve Longerbeam struct ov5640_mode_info {
28519a81c14SSteve Longerbeam 	enum ov5640_mode_id id;
28619a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode;
28722845bf2SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
2883145efcdSJacopo Mondi 	/* Analog crop rectangle. */
2893145efcdSJacopo Mondi 	struct v4l2_rect analog_crop;
2903145efcdSJacopo Mondi 	/* Visibile crop: from analog crop top-left corner. */
2913145efcdSJacopo Mondi 	struct v4l2_rect crop;
2923145efcdSJacopo Mondi 	/* Total pixels per line: crop.width + fixed hblank. */
293476dec01SMaxime Ripard 	u32 htot;
2943145efcdSJacopo Mondi 	/* Default vertical blanking: frame height = crop.height + vblank. */
2953145efcdSJacopo Mondi 	u32 vblank_def;
29619a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
29719a81c14SSteve Longerbeam 	u32 reg_data_size;
2983145efcdSJacopo Mondi 	/* DVP only; ignored in MIPI mode. */
2995554c80eSAdam Ford 	u32 max_fps;
30019a81c14SSteve Longerbeam };
30119a81c14SSteve Longerbeam 
30219a81c14SSteve Longerbeam struct ov5640_ctrls {
30319a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
304cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
3057a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
30619a81c14SSteve Longerbeam 	struct {
30719a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
30819a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
30919a81c14SSteve Longerbeam 	};
31019a81c14SSteve Longerbeam 	struct {
31119a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
31219a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
31319a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
31419a81c14SSteve Longerbeam 	};
31519a81c14SSteve Longerbeam 	struct {
31619a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
31719a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
31819a81c14SSteve Longerbeam 	};
31919a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3201068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
32119a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
32219a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
32319a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
32419a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
325ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
326ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
32719a81c14SSteve Longerbeam };
32819a81c14SSteve Longerbeam 
32919a81c14SSteve Longerbeam struct ov5640_dev {
33019a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
33119a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
33219a81c14SSteve Longerbeam 	struct media_pad pad;
33319a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
33419a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
33519a81c14SSteve Longerbeam 	u32 xclk_freq;
33619a81c14SSteve Longerbeam 
33719a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
33819a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
33919a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
340c3f3ba3eSHugues Fruchet 	bool   upside_down;
34119a81c14SSteve Longerbeam 
34219a81c14SSteve Longerbeam 	/* lock to protect all members below */
34319a81c14SSteve Longerbeam 	struct mutex lock;
34419a81c14SSteve Longerbeam 
34519a81c14SSteve Longerbeam 	int power_count;
34619a81c14SSteve Longerbeam 
34719a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
348fb98e29fSHugues Fruchet 	bool pending_fmt_change;
34919a81c14SSteve Longerbeam 
35019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
351985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
35219a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
35319a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3543c28588fSJacopo Mondi 	s64 current_link_freq;
35519a81c14SSteve Longerbeam 
35619a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
35719a81c14SSteve Longerbeam 
35819a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
35919a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
36019a81c14SSteve Longerbeam 
36119a81c14SSteve Longerbeam 	bool pending_mode_change;
36219a81c14SSteve Longerbeam 	bool streaming;
36319a81c14SSteve Longerbeam };
36419a81c14SSteve Longerbeam 
36519a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
36619a81c14SSteve Longerbeam {
36719a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
36819a81c14SSteve Longerbeam }
36919a81c14SSteve Longerbeam 
37019a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
37119a81c14SSteve Longerbeam {
37219a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
37319a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
37419a81c14SSteve Longerbeam }
37519a81c14SSteve Longerbeam 
3768e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
3778e823f5cSJacopo Mondi {
3788e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
3798e823f5cSJacopo Mondi }
3808e823f5cSJacopo Mondi 
38119a81c14SSteve Longerbeam /*
38219a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
38319a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
38419a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
38519a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
38619a81c14SSteve Longerbeam  * over i2c.
38719a81c14SSteve Longerbeam  */
388fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
38919a81c14SSteve Longerbeam static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
39019a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
391576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
39219a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
39319a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
39419a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
39519a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
39619a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
39719a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
39819a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
39919a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
40019a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
40119a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
40219a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
40319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
40419a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
4053145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
40619a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
40719a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
40819a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
40919a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
41019a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
41119a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
41219a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
413aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4142b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
41519a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
416aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
41719a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
41819a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
41919a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
42019a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
42119a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
42219a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
42319a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
42419a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
42519a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
42619a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
42719a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
42819a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
42919a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
43019a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
43119a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
43219a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
43319a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
43419a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
43519a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
43619a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
43719a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
43819a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
43919a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
44019a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
44119a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
44319a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
44419a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
44519a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
44619a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
44719a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
44819a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
44919a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
45019a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
45119a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
45219a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
45319a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
45519a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
45619a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
45719a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
45819a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
45919a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
46019a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
46119a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
46219a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
46319a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
46419a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
46519a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
46619a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
46719a81c14SSteve Longerbeam };
46819a81c14SSteve Longerbeam 
469086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_VGA_640_480[] = {
470c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
47119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
472ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
4733145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
47419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
47519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
47619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
47719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
47819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4792b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
48019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
48119a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
48219a81c14SSteve Longerbeam };
48319a81c14SSteve Longerbeam 
484086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_XGA_1024_768[] = {
485c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
48619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
487ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
4883145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
48919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
49019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
49119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
49219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
49319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4942b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
49519a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
49686633417SMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
49719a81c14SSteve Longerbeam };
49819a81c14SSteve Longerbeam 
499086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QVGA_320_240[] = {
500c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
50119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
502ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5033145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
50419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
50519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
50619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
50719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5092b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
51119a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
51219a81c14SSteve Longerbeam };
51319a81c14SSteve Longerbeam 
51432ea5e05SHugues Fruchet static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
51532ea5e05SHugues Fruchet 	{0x3c07, 0x08, 0, 0},
51632ea5e05SHugues Fruchet 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
51732ea5e05SHugues Fruchet 	{0x3814, 0x31, 0, 0},
5183145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
51932ea5e05SHugues Fruchet 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
52032ea5e05SHugues Fruchet 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
52132ea5e05SHugues Fruchet 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
52232ea5e05SHugues Fruchet 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
52332ea5e05SHugues Fruchet 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
52432ea5e05SHugues Fruchet 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
52532ea5e05SHugues Fruchet 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
52632ea5e05SHugues Fruchet };
52732ea5e05SHugues Fruchet 
528086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QCIF_176_144[] = {
529c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
53019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
531ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5323145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
53319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
53419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
53519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
53619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
53719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5382b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
53919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
54119a81c14SSteve Longerbeam };
54219a81c14SSteve Longerbeam 
543086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_NTSC_720_480[] = {
544c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
546ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5473145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
55019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
55119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5532b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
55419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55519a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
55619a81c14SSteve Longerbeam };
55719a81c14SSteve Longerbeam 
558086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_PAL_720_576[] = {
559c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
56019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
561ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5623145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
56319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
56419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
56719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5682b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
56919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57019a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
57119a81c14SSteve Longerbeam };
57219a81c14SSteve Longerbeam 
573086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
574c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
57519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
576ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
5773145efcdSJacopo Mondi 	{0x3815, 0x31, 0, 0},
57819a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
57919a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
58019a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
58119a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
58219a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
5832b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
58419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
58519a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
58619a81c14SSteve Longerbeam };
58719a81c14SSteve Longerbeam 
588086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
589c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
59019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
591ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
5923145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
59319a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
59419a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
59519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
59619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
59719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5982b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
59919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
600c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
601c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
60219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
603476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
60419a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
60519a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
60619a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6072b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
60819a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
60992b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
61019a81c14SSteve Longerbeam };
61119a81c14SSteve Longerbeam 
612086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
613c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
61419a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
615ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
6163145efcdSJacopo Mondi 	{0x3815, 0x11, 0, 0},
61719a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
61819a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
61919a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
62019a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
62119a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6222b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
62319a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
62419a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
62519a81c14SSteve Longerbeam };
62619a81c14SSteve Longerbeam 
62719a81c14SSteve Longerbeam /* power-on sensor init reg table */
62819a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = {
6293145efcdSJacopo Mondi 		.id		= 0,
6303145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6313145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
6323145efcdSJacopo Mondi 		.analog_crop = {
6333145efcdSJacopo Mondi 			.left	= 0,
6343145efcdSJacopo Mondi 			.top	= 4,
6353145efcdSJacopo Mondi 			.width	= 2624,
6363145efcdSJacopo Mondi 			.height	= 1944,
6373145efcdSJacopo Mondi 		},
6383145efcdSJacopo Mondi 		.crop = {
6393145efcdSJacopo Mondi 			.left	= 16,
6403145efcdSJacopo Mondi 			.top	= 6,
6413145efcdSJacopo Mondi 			.width	= 640,
6423145efcdSJacopo Mondi 			.height	= 480,
6433145efcdSJacopo Mondi 		},
6443145efcdSJacopo Mondi 		.htot		= 1896,
6453145efcdSJacopo Mondi 		.vblank_def	= 504,
6463145efcdSJacopo Mondi 		.reg_data	= ov5640_init_setting_30fps_VGA,
6473145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
6483145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
64919a81c14SSteve Longerbeam };
65019a81c14SSteve Longerbeam 
65119a81c14SSteve Longerbeam static const struct ov5640_mode_info
652086c25f8SMaxime Ripard ov5640_mode_data[OV5640_NUM_MODES] = {
6538409d017SJacopo Mondi 	{
6548409d017SJacopo Mondi 		/* 160x120 */
6553145efcdSJacopo Mondi 		.id		= OV5640_MODE_QQVGA_160_120,
6563145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6573145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6583145efcdSJacopo Mondi 		.analog_crop = {
6593145efcdSJacopo Mondi 			.left	= 0,
6603145efcdSJacopo Mondi 			.top	= 4,
6613145efcdSJacopo Mondi 			.width	= 2624,
6623145efcdSJacopo Mondi 			.height	= 1944,
6633145efcdSJacopo Mondi 		},
6643145efcdSJacopo Mondi 		.crop = {
6653145efcdSJacopo Mondi 			.left	= 16,
6663145efcdSJacopo Mondi 			.top	= 6,
6673145efcdSJacopo Mondi 			.width	= 160,
6683145efcdSJacopo Mondi 			.height	= 120,
6693145efcdSJacopo Mondi 		},
6703145efcdSJacopo Mondi 		.htot		= 1896,
6713145efcdSJacopo Mondi 		.vblank_def	= 864,
6723145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QQVGA_160_120,
6733145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
6743145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6758409d017SJacopo Mondi 	}, {
6768409d017SJacopo Mondi 		/* 176x144 */
6773145efcdSJacopo Mondi 		.id		= OV5640_MODE_QCIF_176_144,
6783145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
6793145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
6803145efcdSJacopo Mondi 		.analog_crop = {
6813145efcdSJacopo Mondi 			.left	= 0,
6823145efcdSJacopo Mondi 			.top	= 4,
6833145efcdSJacopo Mondi 			.width	= 2624,
6843145efcdSJacopo Mondi 			.height	= 1944,
6853145efcdSJacopo Mondi 		},
6863145efcdSJacopo Mondi 		.crop = {
6873145efcdSJacopo Mondi 			.left	= 16,
6883145efcdSJacopo Mondi 			.top	= 6,
6893145efcdSJacopo Mondi 			.width	= 176,
6903145efcdSJacopo Mondi 			.height	= 144,
6913145efcdSJacopo Mondi 		},
6923145efcdSJacopo Mondi 		.htot		= 1896,
6933145efcdSJacopo Mondi 		.vblank_def	= 840,
6943145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QCIF_176_144,
6953145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QCIF_176_144),
6963145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
6978409d017SJacopo Mondi 	}, {
6988409d017SJacopo Mondi 		/* 320x240 */
6993145efcdSJacopo Mondi 		.id		= OV5640_MODE_QVGA_320_240,
7003145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7013145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7023145efcdSJacopo Mondi 		.analog_crop = {
7033145efcdSJacopo Mondi 			.left	= 0,
7043145efcdSJacopo Mondi 			.top	= 4,
7053145efcdSJacopo Mondi 			.width	= 2624,
7063145efcdSJacopo Mondi 			.height	= 1944,
7073145efcdSJacopo Mondi 		},
7083145efcdSJacopo Mondi 		.crop = {
7093145efcdSJacopo Mondi 			.left	= 16,
7103145efcdSJacopo Mondi 			.top	= 6,
7113145efcdSJacopo Mondi 			.width	= 320,
7123145efcdSJacopo Mondi 			.height	= 240,
7133145efcdSJacopo Mondi 		},
7143145efcdSJacopo Mondi 		.htot		= 1896,
7153145efcdSJacopo Mondi 		.vblank_def	= 744,
7163145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QVGA_320_240,
7173145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QVGA_320_240),
7183145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7198409d017SJacopo Mondi 	}, {
7208409d017SJacopo Mondi 		/* 640x480 */
7213145efcdSJacopo Mondi 		.id		= OV5640_MODE_VGA_640_480,
7223145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7233145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_48M,
7243145efcdSJacopo Mondi 		.analog_crop = {
7253145efcdSJacopo Mondi 			.left	= 0,
7263145efcdSJacopo Mondi 			.top	= 4,
7273145efcdSJacopo Mondi 			.width	= 2624,
7283145efcdSJacopo Mondi 			.height	= 1944,
7293145efcdSJacopo Mondi 		},
7303145efcdSJacopo Mondi 		.crop = {
7313145efcdSJacopo Mondi 			.left	= 16,
7323145efcdSJacopo Mondi 			.top	= 6,
7333145efcdSJacopo Mondi 			.width	= 640,
7343145efcdSJacopo Mondi 			.height	= 480,
7353145efcdSJacopo Mondi 		},
7363145efcdSJacopo Mondi 		.htot		= 1896,
7373145efcdSJacopo Mondi 		.vblank_def	= 600,
7383145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_VGA_640_480,
7393145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_VGA_640_480),
7403145efcdSJacopo Mondi 		.max_fps	= OV5640_60_FPS
7418409d017SJacopo Mondi 	}, {
7428409d017SJacopo Mondi 		/* 720x480 */
7433145efcdSJacopo Mondi 		.id		= OV5640_MODE_NTSC_720_480,
7443145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7453145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7463145efcdSJacopo Mondi 		.analog_crop = {
7473145efcdSJacopo Mondi 			.left	= 0,
7483145efcdSJacopo Mondi 			.top	= 4,
7493145efcdSJacopo Mondi 			.width	= 2624,
7503145efcdSJacopo Mondi 			.height	= 1944,
7513145efcdSJacopo Mondi 		},
7523145efcdSJacopo Mondi 		.crop = {
753*e74ef55bSJacopo Mondi 			.left	= 56,
7543145efcdSJacopo Mondi 			.top	= 60,
7553145efcdSJacopo Mondi 			.width	= 720,
7563145efcdSJacopo Mondi 			.height	= 480,
7573145efcdSJacopo Mondi 		},
7583145efcdSJacopo Mondi 		.htot		= 1896,
7593145efcdSJacopo Mondi 		.vblank_def	= 504,
7603145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_NTSC_720_480,
7613145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_NTSC_720_480),
7623145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7638409d017SJacopo Mondi 	}, {
7648409d017SJacopo Mondi 		/* 720x576 */
7653145efcdSJacopo Mondi 		.id		= OV5640_MODE_PAL_720_576,
7663145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7673145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7683145efcdSJacopo Mondi 		.analog_crop = {
7693145efcdSJacopo Mondi 			.left	= 0,
7703145efcdSJacopo Mondi 			.top	= 4,
7713145efcdSJacopo Mondi 			.width	= 2624,
7723145efcdSJacopo Mondi 			.height	= 1944,
7733145efcdSJacopo Mondi 		},
7743145efcdSJacopo Mondi 		.crop = {
7753145efcdSJacopo Mondi 			.left	= 56,
7763145efcdSJacopo Mondi 			.top	= 6,
7773145efcdSJacopo Mondi 			.width	= 720,
7783145efcdSJacopo Mondi 			.height	= 576,
7793145efcdSJacopo Mondi 		},
7803145efcdSJacopo Mondi 		.htot		= 1896,
7813145efcdSJacopo Mondi 		.vblank_def	= 408,
7823145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_PAL_720_576,
7833145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_PAL_720_576),
7843145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
7858409d017SJacopo Mondi 	}, {
7868409d017SJacopo Mondi 		/* 1024x768 */
7873145efcdSJacopo Mondi 		.id		= OV5640_MODE_XGA_1024_768,
7883145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
7893145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_96M,
7903145efcdSJacopo Mondi 		.analog_crop = {
7913145efcdSJacopo Mondi 			.left	= 0,
7923145efcdSJacopo Mondi 			.top	= 4,
7933145efcdSJacopo Mondi 			.width	= 2624,
7943145efcdSJacopo Mondi 			.height	= 1944,
7953145efcdSJacopo Mondi 		},
7963145efcdSJacopo Mondi 		.crop = {
7973145efcdSJacopo Mondi 			.left	= 16,
7983145efcdSJacopo Mondi 			.top	= 6,
7993145efcdSJacopo Mondi 			.width	= 1024,
8003145efcdSJacopo Mondi 			.height	= 768,
8013145efcdSJacopo Mondi 		},
8023145efcdSJacopo Mondi 		.htot		= 1896,
8033145efcdSJacopo Mondi 		.vblank_def	= 312,
8043145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_XGA_1024_768,
8053145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_XGA_1024_768),
8063145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8078409d017SJacopo Mondi 	}, {
8088409d017SJacopo Mondi 		/* 1280x720 */
8093145efcdSJacopo Mondi 		.id		= OV5640_MODE_720P_1280_720,
8103145efcdSJacopo Mondi 		.dn_mode	= SUBSAMPLING,
8113145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_124M,
8123145efcdSJacopo Mondi 		.analog_crop = {
8133145efcdSJacopo Mondi 			.left	= 0,
8143145efcdSJacopo Mondi 			.top	= 250,
8153145efcdSJacopo Mondi 			.width	= 2624,
8163145efcdSJacopo Mondi 			.height	= 1456,
8173145efcdSJacopo Mondi 		},
8183145efcdSJacopo Mondi 		.crop = {
8193145efcdSJacopo Mondi 			.left	= 16,
8203145efcdSJacopo Mondi 			.top	= 4,
8213145efcdSJacopo Mondi 			.width	= 1280,
8223145efcdSJacopo Mondi 			.height	= 720,
8233145efcdSJacopo Mondi 		},
8243145efcdSJacopo Mondi 		.htot		= 1892,
8253145efcdSJacopo Mondi 		.vblank_def	= 20,
8263145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_720P_1280_720,
8273145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_720P_1280_720),
8283145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8298409d017SJacopo Mondi 	}, {
8308409d017SJacopo Mondi 		/* 1920x1080 */
8313145efcdSJacopo Mondi 		.id		= OV5640_MODE_1080P_1920_1080,
8323145efcdSJacopo Mondi 		.dn_mode	= SCALING,
8333145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_148M,
8343145efcdSJacopo Mondi 		.analog_crop = {
8353145efcdSJacopo Mondi 			.left	= 336,
8363145efcdSJacopo Mondi 			.top	= 434,
8373145efcdSJacopo Mondi 			.width	= 1952,
8383145efcdSJacopo Mondi 			.height	= 1088,
8393145efcdSJacopo Mondi 		},
8403145efcdSJacopo Mondi 		.crop = {
8413145efcdSJacopo Mondi 			.left	= 16,
8423145efcdSJacopo Mondi 			.top	= 4,
8433145efcdSJacopo Mondi 			.width	= 1920,
8443145efcdSJacopo Mondi 			.height	= 1080,
8453145efcdSJacopo Mondi 		},
8463145efcdSJacopo Mondi 		.htot		= 2500,
8473145efcdSJacopo Mondi 		.vblank_def	= 40,
8483145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_1080P_1920_1080,
8493145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
8503145efcdSJacopo Mondi 		.max_fps	= OV5640_30_FPS
8518409d017SJacopo Mondi 	}, {
8528409d017SJacopo Mondi 		/* 2592x1944 */
8533145efcdSJacopo Mondi 		.id		= OV5640_MODE_QSXGA_2592_1944,
8543145efcdSJacopo Mondi 		.dn_mode	= SCALING,
8553145efcdSJacopo Mondi 		.pixel_rate	= OV5640_PIXEL_RATE_168M,
8563145efcdSJacopo Mondi 		.analog_crop = {
8573145efcdSJacopo Mondi 			.left	= 0,
8583145efcdSJacopo Mondi 			.top	= 0,
8593145efcdSJacopo Mondi 			.width	= 2624,
8603145efcdSJacopo Mondi 			.height	= 1952,
8613145efcdSJacopo Mondi 		},
8623145efcdSJacopo Mondi 		.crop = {
8633145efcdSJacopo Mondi 			.left	= 16,
8643145efcdSJacopo Mondi 			.top	= 4,
8653145efcdSJacopo Mondi 			.width	= 2592,
8663145efcdSJacopo Mondi 			.height	= 1944,
8673145efcdSJacopo Mondi 		},
8683145efcdSJacopo Mondi 		.htot		= 2844,
8693145efcdSJacopo Mondi 		.vblank_def	= 24,
8703145efcdSJacopo Mondi 		.reg_data	= ov5640_setting_QSXGA_2592_1944,
8713145efcdSJacopo Mondi 		.reg_data_size	= ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
8723145efcdSJacopo Mondi 		.max_fps	= OV5640_15_FPS
8738409d017SJacopo Mondi 	},
87419a81c14SSteve Longerbeam };
87519a81c14SSteve Longerbeam 
87619a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
87719a81c14SSteve Longerbeam {
87819a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
87919a81c14SSteve Longerbeam 	struct i2c_msg msg;
88019a81c14SSteve Longerbeam 	u8 buf[3];
88119a81c14SSteve Longerbeam 	int ret;
88219a81c14SSteve Longerbeam 
88319a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
88419a81c14SSteve Longerbeam 		return 0;
88519a81c14SSteve Longerbeam 
88619a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
88719a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
88819a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
88919a81c14SSteve Longerbeam 
89019a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
89119a81c14SSteve Longerbeam 	msg.flags = 0;
89219a81c14SSteve Longerbeam 	msg.buf = buf;
89319a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
89419a81c14SSteve Longerbeam 
89519a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
89619a81c14SSteve Longerbeam 	if (ret < 0) {
89719a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
89819a81c14SSteve Longerbeam 		return ret;
89919a81c14SSteve Longerbeam 	}
90019a81c14SSteve Longerbeam 
90119a81c14SSteve Longerbeam 	return 0;
90219a81c14SSteve Longerbeam }
90319a81c14SSteve Longerbeam 
90419a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
90519a81c14SSteve Longerbeam {
90619a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
90719a81c14SSteve Longerbeam 	struct i2c_msg msg;
90819a81c14SSteve Longerbeam 	u8 buf[3];
90919a81c14SSteve Longerbeam 	int ret;
91019a81c14SSteve Longerbeam 
91119a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
91219a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
91319a81c14SSteve Longerbeam 	buf[2] = val;
91419a81c14SSteve Longerbeam 
91519a81c14SSteve Longerbeam 	msg.addr = client->addr;
91619a81c14SSteve Longerbeam 	msg.flags = client->flags;
91719a81c14SSteve Longerbeam 	msg.buf = buf;
91819a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
91919a81c14SSteve Longerbeam 
92019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
92119a81c14SSteve Longerbeam 	if (ret < 0) {
9223924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
92319a81c14SSteve Longerbeam 			__func__, reg, val);
92419a81c14SSteve Longerbeam 		return ret;
92519a81c14SSteve Longerbeam 	}
92619a81c14SSteve Longerbeam 
92719a81c14SSteve Longerbeam 	return 0;
92819a81c14SSteve Longerbeam }
92919a81c14SSteve Longerbeam 
93019a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
93119a81c14SSteve Longerbeam {
93219a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
93319a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
93419a81c14SSteve Longerbeam 	u8 buf[2];
93519a81c14SSteve Longerbeam 	int ret;
93619a81c14SSteve Longerbeam 
93719a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
93819a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
93919a81c14SSteve Longerbeam 
94019a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
94119a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
94219a81c14SSteve Longerbeam 	msg[0].buf = buf;
94319a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
94419a81c14SSteve Longerbeam 
94519a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
94619a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
94719a81c14SSteve Longerbeam 	msg[1].buf = buf;
94819a81c14SSteve Longerbeam 	msg[1].len = 1;
94919a81c14SSteve Longerbeam 
95019a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
9513924c623SHugues Fruchet 	if (ret < 0) {
9523924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
9533924c623SHugues Fruchet 			__func__, reg);
95419a81c14SSteve Longerbeam 		return ret;
9553924c623SHugues Fruchet 	}
95619a81c14SSteve Longerbeam 
95719a81c14SSteve Longerbeam 	*val = buf[0];
95819a81c14SSteve Longerbeam 	return 0;
95919a81c14SSteve Longerbeam }
96019a81c14SSteve Longerbeam 
96119a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
96219a81c14SSteve Longerbeam {
96319a81c14SSteve Longerbeam 	u8 hi, lo;
96419a81c14SSteve Longerbeam 	int ret;
96519a81c14SSteve Longerbeam 
96619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
96719a81c14SSteve Longerbeam 	if (ret)
96819a81c14SSteve Longerbeam 		return ret;
96919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
97019a81c14SSteve Longerbeam 	if (ret)
97119a81c14SSteve Longerbeam 		return ret;
97219a81c14SSteve Longerbeam 
97319a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
97419a81c14SSteve Longerbeam 	return 0;
97519a81c14SSteve Longerbeam }
97619a81c14SSteve Longerbeam 
97719a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
97819a81c14SSteve Longerbeam {
97919a81c14SSteve Longerbeam 	int ret;
98019a81c14SSteve Longerbeam 
98119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
98219a81c14SSteve Longerbeam 	if (ret)
98319a81c14SSteve Longerbeam 		return ret;
98419a81c14SSteve Longerbeam 
98519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
98619a81c14SSteve Longerbeam }
98719a81c14SSteve Longerbeam 
98819a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
98919a81c14SSteve Longerbeam 			  u8 mask, u8 val)
99019a81c14SSteve Longerbeam {
99119a81c14SSteve Longerbeam 	u8 readval;
99219a81c14SSteve Longerbeam 	int ret;
99319a81c14SSteve Longerbeam 
99419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
99519a81c14SSteve Longerbeam 	if (ret)
99619a81c14SSteve Longerbeam 		return ret;
99719a81c14SSteve Longerbeam 
99819a81c14SSteve Longerbeam 	readval &= ~mask;
99919a81c14SSteve Longerbeam 	val &= mask;
100019a81c14SSteve Longerbeam 	val |= readval;
100119a81c14SSteve Longerbeam 
100219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
100319a81c14SSteve Longerbeam }
100419a81c14SSteve Longerbeam 
1005aa288248SMaxime Ripard /*
1006aa288248SMaxime Ripard  * After trying the various combinations, reading various
1007f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
1008aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
1009aa288248SMaxime Ripard  *
1010aa288248SMaxime Ripard  *   +--------------+
1011aa288248SMaxime Ripard  *   |  Ext. Clock  |
1012aa288248SMaxime Ripard  *   +-+------------+
1013aa288248SMaxime Ripard  *     |  +----------+
1014aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
1015aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
1016aa288248SMaxime Ripard  *          |  +--------------+
1017aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
1018aa288248SMaxime Ripard  *             +-+------------+
1019aa288248SMaxime Ripard  *               |  +--------------+
1020aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
1021aa288248SMaxime Ripard  *               |  +-+------------+
1022aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
1023aa288248SMaxime Ripard  *               |    +  +-----+
1024aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
1025aa288248SMaxime Ripard  *               |       +-----+
1026aa288248SMaxime Ripard  *               |  +--------------+
1027aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
1028aa288248SMaxime Ripard  *                  +-+------------+
1029aa288248SMaxime Ripard  *                    |  +---------+
10304c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
1031aa288248SMaxime Ripard  *                       +-+-------+
1032aa288248SMaxime Ripard  *                         |  +-------------+
1033aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
1034aa288248SMaxime Ripard  *                         |  +-+-----------+
1035aa288248SMaxime Ripard  *                         |    +---------------> SCLK
1036aa288248SMaxime Ripard  *                         |  +-------------+
1037aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
1038aa288248SMaxime Ripard  *                         |  +-+-----------+
1039aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
1040aa288248SMaxime Ripard  *                         |  +-------------+
1041aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
1042aa288248SMaxime Ripard  *                            ++------------+
1043aa288248SMaxime Ripard  *                             +  +-----------+
1044aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
1045aa288248SMaxime Ripard  *                                +-----+-----+
1046aa288248SMaxime Ripard  *                                       +------------> PCLK
1047aa288248SMaxime Ripard  *
10486c957ed7SJacopo Mondi  * There seems to be also constraints:
1049aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
1050aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
1051aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
1052aa288248SMaxime Ripard  */
1053aa288248SMaxime Ripard 
1054aa288248SMaxime Ripard /*
1055aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1056aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
1057aa288248SMaxime Ripard  */
1058aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
1059aa288248SMaxime Ripard 
1060aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
1061aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
1062aa288248SMaxime Ripard 
1063aa288248SMaxime Ripard /*
1064aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
1065aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
1066aa288248SMaxime Ripard  */
1067aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
1068aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
1069aa288248SMaxime Ripard 
1070aa288248SMaxime Ripard /*
1071aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
1072aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1073aa288248SMaxime Ripard  */
1074aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
1075aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
1076aa288248SMaxime Ripard 
1077aa288248SMaxime Ripard /*
1078aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
1079aa288248SMaxime Ripard  */
1080aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
1081aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
1082aa288248SMaxime Ripard 
1083aa288248SMaxime Ripard /*
1084aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1085aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
1086aa288248SMaxime Ripard  */
1087aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
1088aa288248SMaxime Ripard 
1089aa288248SMaxime Ripard /*
1090aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
1091aa288248SMaxime Ripard  * SCLK 2x.
1092aa288248SMaxime Ripard  */
1093aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
1094aa288248SMaxime Ripard 
1095aa288248SMaxime Ripard /*
1096aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
1097aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
1098aa288248SMaxime Ripard  */
1099aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
1100aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
1101aa288248SMaxime Ripard 
1102aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1103aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1104aa288248SMaxime Ripard 					    u8 sysdiv)
1105aa288248SMaxime Ripard {
1106aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1107aa288248SMaxime Ripard 
1108aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1109aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1110aa288248SMaxime Ripard 		return 0;
1111aa288248SMaxime Ripard 
1112aa288248SMaxime Ripard 	return sysclk / sysdiv;
1113aa288248SMaxime Ripard }
1114aa288248SMaxime Ripard 
1115aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1116aa288248SMaxime Ripard 					 unsigned long rate,
1117aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1118aa288248SMaxime Ripard 					 u8 *sysdiv)
1119aa288248SMaxime Ripard {
1120aa288248SMaxime Ripard 	unsigned long best = ~0;
1121aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1122aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1123aa288248SMaxime Ripard 
1124aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1125aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1126aa288248SMaxime Ripard 	     _sysdiv++) {
1127aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1128aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1129aa288248SMaxime Ripard 		     _pll_mult++) {
1130aa288248SMaxime Ripard 			unsigned long _rate;
1131aa288248SMaxime Ripard 
1132aa288248SMaxime Ripard 			/*
1133aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1134aa288248SMaxime Ripard 			 * 127.
1135aa288248SMaxime Ripard 			 */
1136aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1137aa288248SMaxime Ripard 				continue;
1138aa288248SMaxime Ripard 
1139aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1140aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1141aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1142aa288248SMaxime Ripard 
1143aa288248SMaxime Ripard 			/*
1144aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1145aa288248SMaxime Ripard 			 * increase sysdiv.
1146aa288248SMaxime Ripard 			 */
11472e3df204SAdam Ford 			if (!_rate)
1148aa288248SMaxime Ripard 				break;
1149aa288248SMaxime Ripard 
1150aa288248SMaxime Ripard 			/*
1151aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1152aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1153aa288248SMaxime Ripard 			 */
1154aa288248SMaxime Ripard 			if (_rate < rate)
1155aa288248SMaxime Ripard 				continue;
1156aa288248SMaxime Ripard 
1157aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1158aa288248SMaxime Ripard 				best = _rate;
1159aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1160aa288248SMaxime Ripard 				best_mult = _pll_mult;
1161aa288248SMaxime Ripard 			}
1162aa288248SMaxime Ripard 
1163aa288248SMaxime Ripard 			if (_rate == rate)
1164aa288248SMaxime Ripard 				goto out;
1165aa288248SMaxime Ripard 		}
1166aa288248SMaxime Ripard 	}
1167aa288248SMaxime Ripard 
1168aa288248SMaxime Ripard out:
1169aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1170aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1171aa288248SMaxime Ripard 	*pll_mult = best_mult;
1172aa288248SMaxime Ripard 
1173aa288248SMaxime Ripard 	return best;
1174aa288248SMaxime Ripard }
1175aa288248SMaxime Ripard 
1176aa288248SMaxime Ripard /*
1177aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1178aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1179aa288248SMaxime Ripard  */
11806c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1181aa288248SMaxime Ripard {
11826c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1183aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
11846c957ed7SJacopo Mondi 	unsigned long link_freq;
11856c957ed7SJacopo Mondi 	unsigned long sysclk;
11866c957ed7SJacopo Mondi 	u8 pclk_period;
11876c957ed7SJacopo Mondi 	u32 sample_rate;
11886c957ed7SJacopo Mondi 	u32 num_lanes;
1189aa288248SMaxime Ripard 	int ret;
1190aa288248SMaxime Ripard 
11916c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
11926c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
11936c957ed7SJacopo Mondi 
1194aa288248SMaxime Ripard 	/*
11956c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
11966c957ed7SJacopo Mondi 	 *
11976c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
11986c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1199aa288248SMaxime Ripard 	 */
12006c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
12016c957ed7SJacopo Mondi 		mipi_div = 1;
1202aa288248SMaxime Ripard 	else
12036c957ed7SJacopo Mondi 		mipi_div = 2;
1204aa288248SMaxime Ripard 
12056c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
12066c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1207aa288248SMaxime Ripard 
12086c957ed7SJacopo Mondi 	/*
12096c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
12106c957ed7SJacopo Mondi 	 *
12116c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
12126c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
12136c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
12146c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
12156c957ed7SJacopo Mondi 	 *
12166c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
12176c957ed7SJacopo Mondi 	 * of lanes:
12186c957ed7SJacopo Mondi 	 *
12196c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
12206c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
12216c957ed7SJacopo Mondi 	 */
12226c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
12236c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
12246c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1225aa288248SMaxime Ripard 
12266c957ed7SJacopo Mondi 	/*
12276c957ed7SJacopo Mondi 	 * Scaler clock:
12286c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
12296c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
12306c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
12316c957ed7SJacopo Mondi 	 */
12326c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
12336c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
12346c957ed7SJacopo Mondi 
12356c957ed7SJacopo Mondi 	/*
12366c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
12376c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
12386c957ed7SJacopo Mondi 	 *
12396c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
12406c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
12416c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
12426c957ed7SJacopo Mondi 	 *
12436c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
12446c957ed7SJacopo Mondi 	 */
12456c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
12466c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
12476c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
12486c957ed7SJacopo Mondi 
12496c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
12506c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
12516c957ed7SJacopo Mondi 	if (ret)
12526c957ed7SJacopo Mondi 		return ret;
12536c957ed7SJacopo Mondi 
12546c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
12556c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1256aa288248SMaxime Ripard 	if (ret)
1257aa288248SMaxime Ripard 		return ret;
1258aa288248SMaxime Ripard 
1259aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1260aa288248SMaxime Ripard 	if (ret)
1261aa288248SMaxime Ripard 		return ret;
1262aa288248SMaxime Ripard 
12636c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
12646c957ed7SJacopo Mondi 			     root_div | prediv);
1265aa288248SMaxime Ripard 	if (ret)
1266aa288248SMaxime Ripard 		return ret;
1267aa288248SMaxime Ripard 
12686c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
12696c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
12706c957ed7SJacopo Mondi 	if (ret)
12716c957ed7SJacopo Mondi 		return ret;
12726c957ed7SJacopo Mondi 
12736c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
12746c957ed7SJacopo Mondi }
12756c957ed7SJacopo Mondi 
12766c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
12776c957ed7SJacopo Mondi {
12783145efcdSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
12796c957ed7SJacopo Mondi 	u32 rate;
12806c957ed7SJacopo Mondi 
12813145efcdSJacopo Mondi 	rate = mode->htot * (mode->crop.height + mode->vblank_def);
12826c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
12836c957ed7SJacopo Mondi 
12846c957ed7SJacopo Mondi 	return rate;
1285aa288248SMaxime Ripard }
1286aa288248SMaxime Ripard 
1287aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1288aa288248SMaxime Ripard 				      unsigned long rate,
1289aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1290aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1291aa288248SMaxime Ripard {
1292aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1293aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1294aa288248SMaxime Ripard 
1295aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1296aa288248SMaxime Ripard 				    sysdiv);
1297aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1298aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1299aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1300aa288248SMaxime Ripard 
1301aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1302aa288248SMaxime Ripard }
1303aa288248SMaxime Ripard 
13046c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1305aa288248SMaxime Ripard {
1306aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
13076c957ed7SJacopo Mondi 	u32 rate;
1308aa288248SMaxime Ripard 	int ret;
1309aa288248SMaxime Ripard 
13106c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
13116c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
13126c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
13136c957ed7SJacopo Mondi 
1314aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1315aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1316aa288248SMaxime Ripard 
1317aa288248SMaxime Ripard 	if (bit_div == 2)
1318aa288248SMaxime Ripard 		bit_div = 8;
1319aa288248SMaxime Ripard 
1320aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1321aa288248SMaxime Ripard 			     0x0f, bit_div);
1322aa288248SMaxime Ripard 	if (ret)
1323aa288248SMaxime Ripard 		return ret;
1324aa288248SMaxime Ripard 
1325aa288248SMaxime Ripard 	/*
1326aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1327aa288248SMaxime Ripard 	 * the MIPI divider.
1328aa288248SMaxime Ripard 	 */
1329aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1330aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1331aa288248SMaxime Ripard 	if (ret)
1332aa288248SMaxime Ripard 		return ret;
1333aa288248SMaxime Ripard 
1334aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1335aa288248SMaxime Ripard 			     0xff, mult);
1336aa288248SMaxime Ripard 	if (ret)
1337aa288248SMaxime Ripard 		return ret;
1338aa288248SMaxime Ripard 
1339aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1340aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1341aa288248SMaxime Ripard 	if (ret)
1342aa288248SMaxime Ripard 		return ret;
1343aa288248SMaxime Ripard 
1344aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1345aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1346aa288248SMaxime Ripard }
1347aa288248SMaxime Ripard 
13487cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
13497cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
13507cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
13517cb013b1SChen-Yu Tsai {
13527cb013b1SChen-Yu Tsai 	int ret;
13537cb013b1SChen-Yu Tsai 
13542b5c18f9SChen-Yu Tsai 	/*
13552b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
13562b5c18f9SChen-Yu Tsai 	 *
13572b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
13582b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
13592b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
13602b5c18f9SChen-Yu Tsai 	 */
13612b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
13622b5c18f9SChen-Yu Tsai 	if (ret < 0)
13632b5c18f9SChen-Yu Tsai 		return ret;
13642b5c18f9SChen-Yu Tsai 
13653145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE,
13663145efcdSJacopo Mondi 				 mode->crop.width);
13677cb013b1SChen-Yu Tsai 	if (ret < 0)
13687cb013b1SChen-Yu Tsai 		return ret;
13697cb013b1SChen-Yu Tsai 
13703145efcdSJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE,
13713145efcdSJacopo Mondi 				  mode->crop.height);
13727cb013b1SChen-Yu Tsai }
13737cb013b1SChen-Yu Tsai 
137419a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1375bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1376bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1377bad1774eSJacopo Mondi {
13783145efcdSJacopo Mondi 	const struct v4l2_rect *analog_crop = &mode->analog_crop;
13793145efcdSJacopo Mondi 	const struct v4l2_rect *crop = &mode->crop;
1380bad1774eSJacopo Mondi 	int ret;
1381bad1774eSJacopo Mondi 
13827cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
13837cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
13847cb013b1SChen-Yu Tsai 		if (ret < 0)
13857cb013b1SChen-Yu Tsai 			return ret;
13867cb013b1SChen-Yu Tsai 	}
13877cb013b1SChen-Yu Tsai 
13883145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
13893145efcdSJacopo Mondi 				 analog_crop->left);
1390bad1774eSJacopo Mondi 	if (ret < 0)
1391bad1774eSJacopo Mondi 		return ret;
1392bad1774eSJacopo Mondi 
13933145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
13943145efcdSJacopo Mondi 				 analog_crop->top);
13953145efcdSJacopo Mondi 	if (ret < 0)
13963145efcdSJacopo Mondi 		return ret;
13973145efcdSJacopo Mondi 
13983145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
13993145efcdSJacopo Mondi 				 analog_crop->left + analog_crop->width - 1);
14003145efcdSJacopo Mondi 	if (ret < 0)
14013145efcdSJacopo Mondi 		return ret;
14023145efcdSJacopo Mondi 
14033145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
14043145efcdSJacopo Mondi 				 analog_crop->top + analog_crop->height - 1);
14053145efcdSJacopo Mondi 	if (ret < 0)
14063145efcdSJacopo Mondi 		return ret;
14073145efcdSJacopo Mondi 
14083145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
14093145efcdSJacopo Mondi 	if (ret < 0)
14103145efcdSJacopo Mondi 		return ret;
14113145efcdSJacopo Mondi 
14123145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
14133145efcdSJacopo Mondi 	if (ret < 0)
14143145efcdSJacopo Mondi 		return ret;
14153145efcdSJacopo Mondi 
14163145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, crop->width);
14173145efcdSJacopo Mondi 	if (ret < 0)
14183145efcdSJacopo Mondi 		return ret;
14193145efcdSJacopo Mondi 
14203145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, crop->height);
1421bad1774eSJacopo Mondi 	if (ret < 0)
1422bad1774eSJacopo Mondi 		return ret;
1423bad1774eSJacopo Mondi 
1424bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
1425bad1774eSJacopo Mondi 	if (ret < 0)
1426bad1774eSJacopo Mondi 		return ret;
1427bad1774eSJacopo Mondi 
14283145efcdSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
14293145efcdSJacopo Mondi 				 crop->height + mode->vblank_def);
14303145efcdSJacopo Mondi 	if (ret < 0)
14313145efcdSJacopo Mondi 		return ret;
14323145efcdSJacopo Mondi 
14333145efcdSJacopo Mondi 	return 0;
1434bad1774eSJacopo Mondi }
1435bad1774eSJacopo Mondi 
143619a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor,
143719a81c14SSteve Longerbeam 			    const struct ov5640_mode_info *mode)
143819a81c14SSteve Longerbeam {
143919a81c14SSteve Longerbeam 	const struct reg_value *regs = mode->reg_data;
144019a81c14SSteve Longerbeam 	unsigned int i;
144119a81c14SSteve Longerbeam 	u32 delay_ms;
144219a81c14SSteve Longerbeam 	u16 reg_addr;
144319a81c14SSteve Longerbeam 	u8 mask, val;
144419a81c14SSteve Longerbeam 	int ret = 0;
144519a81c14SSteve Longerbeam 
144619a81c14SSteve Longerbeam 	for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
144719a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
144819a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
144919a81c14SSteve Longerbeam 		val = regs->val;
145019a81c14SSteve Longerbeam 		mask = regs->mask;
145119a81c14SSteve Longerbeam 
14523b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
14533b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
14543b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
14558e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
14563b987d70SLad Prabhakar 			continue;
14573b987d70SLad Prabhakar 
145819a81c14SSteve Longerbeam 		if (mask)
145919a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
146019a81c14SSteve Longerbeam 		else
146119a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
146219a81c14SSteve Longerbeam 		if (ret)
146319a81c14SSteve Longerbeam 			break;
146419a81c14SSteve Longerbeam 
146519a81c14SSteve Longerbeam 		if (delay_ms)
146619a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
146719a81c14SSteve Longerbeam 	}
146819a81c14SSteve Longerbeam 
1469bad1774eSJacopo Mondi 	return ov5640_set_timings(sensor, mode);
147019a81c14SSteve Longerbeam }
147119a81c14SSteve Longerbeam 
1472dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1473dc29a1c1SHugues Fruchet {
1474dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1475dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1476dc29a1c1SHugues Fruchet }
1477dc29a1c1SHugues Fruchet 
147819a81c14SSteve Longerbeam /* read exposure, in number of line periods */
147919a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
148019a81c14SSteve Longerbeam {
148119a81c14SSteve Longerbeam 	int exp, ret;
148219a81c14SSteve Longerbeam 	u8 temp;
148319a81c14SSteve Longerbeam 
148419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
148519a81c14SSteve Longerbeam 	if (ret)
148619a81c14SSteve Longerbeam 		return ret;
148719a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
148819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
148919a81c14SSteve Longerbeam 	if (ret)
149019a81c14SSteve Longerbeam 		return ret;
149119a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
149219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
149319a81c14SSteve Longerbeam 	if (ret)
149419a81c14SSteve Longerbeam 		return ret;
149519a81c14SSteve Longerbeam 	exp |= (int)temp;
149619a81c14SSteve Longerbeam 
149719a81c14SSteve Longerbeam 	return exp >> 4;
149819a81c14SSteve Longerbeam }
149919a81c14SSteve Longerbeam 
150019a81c14SSteve Longerbeam /* write exposure, given number of line periods */
150119a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
150219a81c14SSteve Longerbeam {
150319a81c14SSteve Longerbeam 	int ret;
150419a81c14SSteve Longerbeam 
150519a81c14SSteve Longerbeam 	exposure <<= 4;
150619a81c14SSteve Longerbeam 
150719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
150819a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
150919a81c14SSteve Longerbeam 			       exposure & 0xff);
151019a81c14SSteve Longerbeam 	if (ret)
151119a81c14SSteve Longerbeam 		return ret;
151219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
151319a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
151419a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
151519a81c14SSteve Longerbeam 	if (ret)
151619a81c14SSteve Longerbeam 		return ret;
151719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
151819a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
151919a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
152019a81c14SSteve Longerbeam }
152119a81c14SSteve Longerbeam 
152219a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
152319a81c14SSteve Longerbeam {
152419a81c14SSteve Longerbeam 	u16 gain;
152519a81c14SSteve Longerbeam 	int ret;
152619a81c14SSteve Longerbeam 
152719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
152819a81c14SSteve Longerbeam 	if (ret)
152919a81c14SSteve Longerbeam 		return ret;
153019a81c14SSteve Longerbeam 
153119a81c14SSteve Longerbeam 	return gain & 0x3ff;
153219a81c14SSteve Longerbeam }
153319a81c14SSteve Longerbeam 
15343cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
15353cca8ef5SHugues Fruchet {
15363cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
15373cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
15383cca8ef5SHugues Fruchet }
15393cca8ef5SHugues Fruchet 
15403cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
15413cca8ef5SHugues Fruchet {
15423cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
15433cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
15443cca8ef5SHugues Fruchet }
15453cca8ef5SHugues Fruchet 
1546f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1547f22996dbSHugues Fruchet {
15483b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
15493b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
15503b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1551f22996dbSHugues Fruchet }
1552f22996dbSHugues Fruchet 
1553f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
155419a81c14SSteve Longerbeam {
155519a81c14SSteve Longerbeam 	int ret;
155619a81c14SSteve Longerbeam 
1557aa4bb8b8SJacopo Mondi 	/*
1558aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1559aa4bb8b8SJacopo Mondi 	 *
1560aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1561aa4bb8b8SJacopo Mondi 	 *
1562aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1563aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1564aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1565aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1566aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1567aa4bb8b8SJacopo Mondi 	 *
1568aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1569aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1570aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1571aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1572aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1573aa4bb8b8SJacopo Mondi 	 */
1574aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1575aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
157619a81c14SSteve Longerbeam 	if (ret)
157719a81c14SSteve Longerbeam 		return ret;
157819a81c14SSteve Longerbeam 
157919a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
158019a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
158119a81c14SSteve Longerbeam }
158219a81c14SSteve Longerbeam 
158319a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
158419a81c14SSteve Longerbeam {
158519a81c14SSteve Longerbeam 	 /* calculate sysclk */
158619a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
158719a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
158819a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
158919a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
159019a81c14SSteve Longerbeam 	u8 temp1, temp2;
159119a81c14SSteve Longerbeam 	int ret;
159219a81c14SSteve Longerbeam 
159319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
159419a81c14SSteve Longerbeam 	if (ret)
159519a81c14SSteve Longerbeam 		return ret;
159619a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
159719a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
159819a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
159919a81c14SSteve Longerbeam 
160019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
160119a81c14SSteve Longerbeam 	if (ret)
160219a81c14SSteve Longerbeam 		return ret;
160319a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
160419a81c14SSteve Longerbeam 	if (sysdiv == 0)
160519a81c14SSteve Longerbeam 		sysdiv = 16;
160619a81c14SSteve Longerbeam 
160719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
160819a81c14SSteve Longerbeam 	if (ret)
160919a81c14SSteve Longerbeam 		return ret;
161019a81c14SSteve Longerbeam 	multiplier = temp1;
161119a81c14SSteve Longerbeam 
161219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
161319a81c14SSteve Longerbeam 	if (ret)
161419a81c14SSteve Longerbeam 		return ret;
161519a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
161619a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
161719a81c14SSteve Longerbeam 
161819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
161919a81c14SSteve Longerbeam 	if (ret)
162019a81c14SSteve Longerbeam 		return ret;
162119a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
162219a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
162319a81c14SSteve Longerbeam 
162419a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
162519a81c14SSteve Longerbeam 		return -EINVAL;
162619a81c14SSteve Longerbeam 
162719a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
162819a81c14SSteve Longerbeam 
162919a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
163019a81c14SSteve Longerbeam 
163119a81c14SSteve Longerbeam 	return sysclk;
163219a81c14SSteve Longerbeam }
163319a81c14SSteve Longerbeam 
163419a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
163519a81c14SSteve Longerbeam {
163619a81c14SSteve Longerbeam 	 /* read HTS from register settings */
163719a81c14SSteve Longerbeam 	u8 mode;
163819a81c14SSteve Longerbeam 	int ret;
163919a81c14SSteve Longerbeam 
164019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
164119a81c14SSteve Longerbeam 	if (ret)
164219a81c14SSteve Longerbeam 		return ret;
164319a81c14SSteve Longerbeam 	mode &= 0xfb;
164419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
164519a81c14SSteve Longerbeam }
164619a81c14SSteve Longerbeam 
164719a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
164819a81c14SSteve Longerbeam {
164919a81c14SSteve Longerbeam 	/* read HTS from register settings */
165019a81c14SSteve Longerbeam 	u16 hts;
165119a81c14SSteve Longerbeam 	int ret;
165219a81c14SSteve Longerbeam 
165319a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
165419a81c14SSteve Longerbeam 	if (ret)
165519a81c14SSteve Longerbeam 		return ret;
165619a81c14SSteve Longerbeam 	return hts;
165719a81c14SSteve Longerbeam }
165819a81c14SSteve Longerbeam 
165919a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
166019a81c14SSteve Longerbeam {
166119a81c14SSteve Longerbeam 	u16 vts;
166219a81c14SSteve Longerbeam 	int ret;
166319a81c14SSteve Longerbeam 
166419a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
166519a81c14SSteve Longerbeam 	if (ret)
166619a81c14SSteve Longerbeam 		return ret;
166719a81c14SSteve Longerbeam 	return vts;
166819a81c14SSteve Longerbeam }
166919a81c14SSteve Longerbeam 
167019a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
167119a81c14SSteve Longerbeam {
167219a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
167319a81c14SSteve Longerbeam }
167419a81c14SSteve Longerbeam 
167519a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
167619a81c14SSteve Longerbeam {
167719a81c14SSteve Longerbeam 	/* get banding filter value */
167819a81c14SSteve Longerbeam 	int ret, light_freq = 0;
167919a81c14SSteve Longerbeam 	u8 temp, temp1;
168019a81c14SSteve Longerbeam 
168119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
168219a81c14SSteve Longerbeam 	if (ret)
168319a81c14SSteve Longerbeam 		return ret;
168419a81c14SSteve Longerbeam 
168519a81c14SSteve Longerbeam 	if (temp & 0x80) {
168619a81c14SSteve Longerbeam 		/* manual */
168719a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
168819a81c14SSteve Longerbeam 				      &temp1);
168919a81c14SSteve Longerbeam 		if (ret)
169019a81c14SSteve Longerbeam 			return ret;
169119a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
169219a81c14SSteve Longerbeam 			/* 50Hz */
169319a81c14SSteve Longerbeam 			light_freq = 50;
169419a81c14SSteve Longerbeam 		} else {
169519a81c14SSteve Longerbeam 			/* 60Hz */
169619a81c14SSteve Longerbeam 			light_freq = 60;
169719a81c14SSteve Longerbeam 		}
169819a81c14SSteve Longerbeam 	} else {
169919a81c14SSteve Longerbeam 		/* auto */
170019a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
170119a81c14SSteve Longerbeam 				      &temp1);
170219a81c14SSteve Longerbeam 		if (ret)
170319a81c14SSteve Longerbeam 			return ret;
170419a81c14SSteve Longerbeam 
170519a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
170619a81c14SSteve Longerbeam 			/* 50Hz */
170719a81c14SSteve Longerbeam 			light_freq = 50;
170819a81c14SSteve Longerbeam 		} else {
170919a81c14SSteve Longerbeam 			/* 60Hz */
171019a81c14SSteve Longerbeam 		}
171119a81c14SSteve Longerbeam 	}
171219a81c14SSteve Longerbeam 
171319a81c14SSteve Longerbeam 	return light_freq;
171419a81c14SSteve Longerbeam }
171519a81c14SSteve Longerbeam 
171619a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
171719a81c14SSteve Longerbeam {
171819a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
171919a81c14SSteve Longerbeam 	int ret;
172019a81c14SSteve Longerbeam 
172119a81c14SSteve Longerbeam 	/* read preview PCLK */
172219a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
172319a81c14SSteve Longerbeam 	if (ret < 0)
172419a81c14SSteve Longerbeam 		return ret;
172519a81c14SSteve Longerbeam 	if (ret == 0)
172619a81c14SSteve Longerbeam 		return -EINVAL;
172719a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
172819a81c14SSteve Longerbeam 	/* read preview HTS */
172919a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
173019a81c14SSteve Longerbeam 	if (ret < 0)
173119a81c14SSteve Longerbeam 		return ret;
173219a81c14SSteve Longerbeam 	if (ret == 0)
173319a81c14SSteve Longerbeam 		return -EINVAL;
173419a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
173519a81c14SSteve Longerbeam 
173619a81c14SSteve Longerbeam 	/* read preview VTS */
173719a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
173819a81c14SSteve Longerbeam 	if (ret < 0)
173919a81c14SSteve Longerbeam 		return ret;
174019a81c14SSteve Longerbeam 	prev_vts = ret;
174119a81c14SSteve Longerbeam 
174219a81c14SSteve Longerbeam 	/* calculate banding filter */
174319a81c14SSteve Longerbeam 	/* 60Hz */
174419a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
174519a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
174619a81c14SSteve Longerbeam 	if (ret)
174719a81c14SSteve Longerbeam 		return ret;
174819a81c14SSteve Longerbeam 	if (!band_step60)
174919a81c14SSteve Longerbeam 		return -EINVAL;
175019a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
175119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
175219a81c14SSteve Longerbeam 	if (ret)
175319a81c14SSteve Longerbeam 		return ret;
175419a81c14SSteve Longerbeam 
175519a81c14SSteve Longerbeam 	/* 50Hz */
175619a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
175719a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
175819a81c14SSteve Longerbeam 	if (ret)
175919a81c14SSteve Longerbeam 		return ret;
176019a81c14SSteve Longerbeam 	if (!band_step50)
176119a81c14SSteve Longerbeam 		return -EINVAL;
176219a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
176319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
176419a81c14SSteve Longerbeam }
176519a81c14SSteve Longerbeam 
176619a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
176719a81c14SSteve Longerbeam {
176819a81c14SSteve Longerbeam 	/* stable in high */
176919a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
177019a81c14SSteve Longerbeam 	int ret;
177119a81c14SSteve Longerbeam 
177219a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
177319a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
177419a81c14SSteve Longerbeam 
177519a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
177619a81c14SSteve Longerbeam 	if (fast_high > 255)
177719a81c14SSteve Longerbeam 		fast_high = 255;
177819a81c14SSteve Longerbeam 
177919a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
178019a81c14SSteve Longerbeam 
178119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
178219a81c14SSteve Longerbeam 	if (ret)
178319a81c14SSteve Longerbeam 		return ret;
178419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
178519a81c14SSteve Longerbeam 	if (ret)
178619a81c14SSteve Longerbeam 		return ret;
178719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
178819a81c14SSteve Longerbeam 	if (ret)
178919a81c14SSteve Longerbeam 		return ret;
179019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
179119a81c14SSteve Longerbeam 	if (ret)
179219a81c14SSteve Longerbeam 		return ret;
179319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
179419a81c14SSteve Longerbeam 	if (ret)
179519a81c14SSteve Longerbeam 		return ret;
179619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
179719a81c14SSteve Longerbeam }
179819a81c14SSteve Longerbeam 
1799c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
180019a81c14SSteve Longerbeam {
180119a81c14SSteve Longerbeam 	u8 temp;
180219a81c14SSteve Longerbeam 	int ret;
180319a81c14SSteve Longerbeam 
180419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
180519a81c14SSteve Longerbeam 	if (ret)
180619a81c14SSteve Longerbeam 		return ret;
1807c2c3f42dSHugues Fruchet 
1808c2c3f42dSHugues Fruchet 	return temp & BIT(0);
180919a81c14SSteve Longerbeam }
181019a81c14SSteve Longerbeam 
1811ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1812ce85705aSHugues Fruchet {
1813ce85705aSHugues Fruchet 	int ret;
1814ce85705aSHugues Fruchet 
1815ce85705aSHugues Fruchet 	/*
1816ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1817ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1818ce85705aSHugues Fruchet 	 */
1819ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1820ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1821ce85705aSHugues Fruchet 	if (ret)
1822ce85705aSHugues Fruchet 		return ret;
1823ce85705aSHugues Fruchet 	/*
1824ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1825ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1826ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1827ce85705aSHugues Fruchet 	 */
1828ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1829ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1830ce85705aSHugues Fruchet }
1831ce85705aSHugues Fruchet 
183219a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
183319a81c14SSteve Longerbeam {
18348670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
183519a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
183619a81c14SSteve Longerbeam 	int ret;
183719a81c14SSteve Longerbeam 
18388670d70aSHugues Fruchet 	if (channel > 3) {
18398670d70aSHugues Fruchet 		dev_err(&client->dev,
18408670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
18418670d70aSHugues Fruchet 			__func__, channel);
184219a81c14SSteve Longerbeam 		return -EINVAL;
18438670d70aSHugues Fruchet 	}
184419a81c14SSteve Longerbeam 
184519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
184619a81c14SSteve Longerbeam 	if (ret)
184719a81c14SSteve Longerbeam 		return ret;
184819a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
184919a81c14SSteve Longerbeam 	temp |= (channel << 6);
185019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
185119a81c14SSteve Longerbeam }
185219a81c14SSteve Longerbeam 
185319a81c14SSteve Longerbeam static const struct ov5640_mode_info *
185419a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
185519a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
185619a81c14SSteve Longerbeam {
18573c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
185819a81c14SSteve Longerbeam 
1859086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
1860086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
18613145efcdSJacopo Mondi 				      crop.width, crop.height, width, height);
186219a81c14SSteve Longerbeam 
18633c4a7372SHugues Fruchet 	if (!mode ||
18643145efcdSJacopo Mondi 	    (!nearest &&
18653145efcdSJacopo Mondi 	     (mode->crop.width != width || mode->crop.height != height)))
18663c4a7372SHugues Fruchet 		return NULL;
186719a81c14SSteve Longerbeam 
18685554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
18695554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
1870981e4454SBenoit Parrot 		return NULL;
1871981e4454SBenoit Parrot 
187219a81c14SSteve Longerbeam 	return mode;
187319a81c14SSteve Longerbeam }
187419a81c14SSteve Longerbeam 
187519a81c14SSteve Longerbeam /*
187619a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
187719a81c14SSteve Longerbeam  * exposure calculation
187819a81c14SSteve Longerbeam  */
187941d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
188041d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
188119a81c14SSteve Longerbeam {
188219a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
188319a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
188419a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
188519a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
188619a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
188719a81c14SSteve Longerbeam 	u8 average;
188819a81c14SSteve Longerbeam 	int ret;
188919a81c14SSteve Longerbeam 
189041d8d7f5SHugues Fruchet 	if (!mode->reg_data)
189119a81c14SSteve Longerbeam 		return -EINVAL;
189219a81c14SSteve Longerbeam 
189319a81c14SSteve Longerbeam 	/* read preview shutter */
189419a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
189519a81c14SSteve Longerbeam 	if (ret < 0)
189619a81c14SSteve Longerbeam 		return ret;
189719a81c14SSteve Longerbeam 	prev_shutter = ret;
1898c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
189919a81c14SSteve Longerbeam 	if (ret < 0)
190019a81c14SSteve Longerbeam 		return ret;
190119a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
190219a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
190319a81c14SSteve Longerbeam 		prev_shutter *= 2;
190419a81c14SSteve Longerbeam 
190519a81c14SSteve Longerbeam 	/* read preview gain */
190619a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
190719a81c14SSteve Longerbeam 	if (ret < 0)
190819a81c14SSteve Longerbeam 		return ret;
190919a81c14SSteve Longerbeam 	prev_gain16 = ret;
191019a81c14SSteve Longerbeam 
191119a81c14SSteve Longerbeam 	/* get average */
191219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
191319a81c14SSteve Longerbeam 	if (ret)
191419a81c14SSteve Longerbeam 		return ret;
191519a81c14SSteve Longerbeam 
191619a81c14SSteve Longerbeam 	/* turn off night mode for capture */
191719a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
191819a81c14SSteve Longerbeam 	if (ret < 0)
191919a81c14SSteve Longerbeam 		return ret;
192019a81c14SSteve Longerbeam 
192119a81c14SSteve Longerbeam 	/* Write capture setting */
192219a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, mode);
192319a81c14SSteve Longerbeam 	if (ret < 0)
192419a81c14SSteve Longerbeam 		return ret;
192519a81c14SSteve Longerbeam 
192619a81c14SSteve Longerbeam 	/* read capture VTS */
192719a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
192819a81c14SSteve Longerbeam 	if (ret < 0)
192919a81c14SSteve Longerbeam 		return ret;
193019a81c14SSteve Longerbeam 	cap_vts = ret;
193119a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
193219a81c14SSteve Longerbeam 	if (ret < 0)
193319a81c14SSteve Longerbeam 		return ret;
193419a81c14SSteve Longerbeam 	if (ret == 0)
193519a81c14SSteve Longerbeam 		return -EINVAL;
193619a81c14SSteve Longerbeam 	cap_hts = ret;
193719a81c14SSteve Longerbeam 
193819a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
193919a81c14SSteve Longerbeam 	if (ret < 0)
194019a81c14SSteve Longerbeam 		return ret;
194119a81c14SSteve Longerbeam 	if (ret == 0)
194219a81c14SSteve Longerbeam 		return -EINVAL;
194319a81c14SSteve Longerbeam 	cap_sysclk = ret;
194419a81c14SSteve Longerbeam 
194519a81c14SSteve Longerbeam 	/* calculate capture banding filter */
194619a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
194719a81c14SSteve Longerbeam 	if (ret < 0)
194819a81c14SSteve Longerbeam 		return ret;
194919a81c14SSteve Longerbeam 	light_freq = ret;
195019a81c14SSteve Longerbeam 
195119a81c14SSteve Longerbeam 	if (light_freq == 60) {
195219a81c14SSteve Longerbeam 		/* 60Hz */
195319a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
195419a81c14SSteve Longerbeam 	} else {
195519a81c14SSteve Longerbeam 		/* 50Hz */
195619a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
195719a81c14SSteve Longerbeam 	}
195819a81c14SSteve Longerbeam 
195919a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
196019a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
196119a81c14SSteve Longerbeam 		if (ret < 0)
196219a81c14SSteve Longerbeam 			return ret;
196319a81c14SSteve Longerbeam 		if (ret == 0)
196419a81c14SSteve Longerbeam 			return -EINVAL;
196519a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
196619a81c14SSteve Longerbeam 	}
196719a81c14SSteve Longerbeam 
196819a81c14SSteve Longerbeam 	if (!cap_bandfilt)
196919a81c14SSteve Longerbeam 		return -EINVAL;
197019a81c14SSteve Longerbeam 
197119a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
197219a81c14SSteve Longerbeam 
197319a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
197419a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
197519a81c14SSteve Longerbeam 		/* in stable range */
197619a81c14SSteve Longerbeam 		cap_gain16_shutter =
197719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
197819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
197919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
198019a81c14SSteve Longerbeam 			sensor->ae_target / average;
198119a81c14SSteve Longerbeam 	} else {
198219a81c14SSteve Longerbeam 		cap_gain16_shutter =
198319a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
198419a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
198519a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
198619a81c14SSteve Longerbeam 	}
198719a81c14SSteve Longerbeam 
198819a81c14SSteve Longerbeam 	/* gain to shutter */
198919a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
199019a81c14SSteve Longerbeam 		/* shutter < 1/100 */
199119a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
199219a81c14SSteve Longerbeam 		if (cap_shutter < 1)
199319a81c14SSteve Longerbeam 			cap_shutter = 1;
199419a81c14SSteve Longerbeam 
199519a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
199619a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
199719a81c14SSteve Longerbeam 			cap_gain16 = 16;
199819a81c14SSteve Longerbeam 	} else {
199919a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
200019a81c14SSteve Longerbeam 			/* exposure reach max */
200119a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
200219a81c14SSteve Longerbeam 			if (!cap_shutter)
200319a81c14SSteve Longerbeam 				return -EINVAL;
200419a81c14SSteve Longerbeam 
200519a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
200619a81c14SSteve Longerbeam 		} else {
200719a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
200819a81c14SSteve Longerbeam 			cap_shutter =
200919a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
201019a81c14SSteve Longerbeam 				* cap_bandfilt;
201119a81c14SSteve Longerbeam 			if (!cap_shutter)
201219a81c14SSteve Longerbeam 				return -EINVAL;
201319a81c14SSteve Longerbeam 
201419a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
201519a81c14SSteve Longerbeam 		}
201619a81c14SSteve Longerbeam 	}
201719a81c14SSteve Longerbeam 
201819a81c14SSteve Longerbeam 	/* set capture gain */
20193cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
202019a81c14SSteve Longerbeam 	if (ret)
202119a81c14SSteve Longerbeam 		return ret;
202219a81c14SSteve Longerbeam 
202319a81c14SSteve Longerbeam 	/* write capture shutter */
202419a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
202519a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
202619a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
202719a81c14SSteve Longerbeam 		if (ret < 0)
202819a81c14SSteve Longerbeam 			return ret;
202919a81c14SSteve Longerbeam 	}
203019a81c14SSteve Longerbeam 
203119a81c14SSteve Longerbeam 	/* set exposure */
20323cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
203319a81c14SSteve Longerbeam }
203419a81c14SSteve Longerbeam 
203519a81c14SSteve Longerbeam /*
203619a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
203719a81c14SSteve Longerbeam  * change mode directly
203819a81c14SSteve Longerbeam  */
203919a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
20403cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
204119a81c14SSteve Longerbeam {
204241d8d7f5SHugues Fruchet 	if (!mode->reg_data)
204319a81c14SSteve Longerbeam 		return -EINVAL;
204419a81c14SSteve Longerbeam 
204519a81c14SSteve Longerbeam 	/* Write capture setting */
20463cca8ef5SHugues Fruchet 	return ov5640_load_regs(sensor, mode);
204719a81c14SSteve Longerbeam }
204819a81c14SSteve Longerbeam 
2049985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
205019a81c14SSteve Longerbeam {
205119a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
2052985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
205319a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
20543cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
2055dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
205619a81c14SSteve Longerbeam 	int ret;
205719a81c14SSteve Longerbeam 
205819a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
205919a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
206019a81c14SSteve Longerbeam 
206119a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
20623cca8ef5SHugues Fruchet 	if (auto_gain) {
20633cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
206419a81c14SSteve Longerbeam 		if (ret)
206519a81c14SSteve Longerbeam 			return ret;
20663cca8ef5SHugues Fruchet 	}
2067bf4a4b51SMaxime Ripard 
20683cca8ef5SHugues Fruchet 	if (auto_exp) {
2069dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
207019a81c14SSteve Longerbeam 		if (ret)
20713cca8ef5SHugues Fruchet 			goto restore_auto_gain;
20723cca8ef5SHugues Fruchet 	}
207319a81c14SSteve Longerbeam 
20746c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
20756c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
20766c957ed7SJacopo Mondi 	else
20776c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
2078aa288248SMaxime Ripard 	if (ret < 0)
2079aa288248SMaxime Ripard 		return 0;
2080aa288248SMaxime Ripard 
208119a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
208219a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
208319a81c14SSteve Longerbeam 		/*
208419a81c14SSteve Longerbeam 		 * change between subsampling and scaling
20853cca8ef5SHugues Fruchet 		 * go through exposure calculation
208619a81c14SSteve Longerbeam 		 */
208719a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
208819a81c14SSteve Longerbeam 	} else {
208919a81c14SSteve Longerbeam 		/*
209019a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
209119a81c14SSteve Longerbeam 		 * download firmware directly
209219a81c14SSteve Longerbeam 		 */
20933cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
209419a81c14SSteve Longerbeam 	}
209519a81c14SSteve Longerbeam 	if (ret < 0)
20963cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
20973cca8ef5SHugues Fruchet 
20983cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
20993cca8ef5SHugues Fruchet 	if (auto_gain)
21003cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
21013cca8ef5SHugues Fruchet 	if (auto_exp)
21023cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
210319a81c14SSteve Longerbeam 
2104ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
2105ce85705aSHugues Fruchet 	if (ret < 0)
2106ce85705aSHugues Fruchet 		return ret;
210719a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
210819a81c14SSteve Longerbeam 	if (ret < 0)
210919a81c14SSteve Longerbeam 		return ret;
211019a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
211119a81c14SSteve Longerbeam 	if (ret < 0)
211219a81c14SSteve Longerbeam 		return ret;
211319a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
211419a81c14SSteve Longerbeam 	if (ret < 0)
211519a81c14SSteve Longerbeam 		return ret;
211619a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
211719a81c14SSteve Longerbeam 	if (ret < 0)
211819a81c14SSteve Longerbeam 		return ret;
211919a81c14SSteve Longerbeam 
212019a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
2121985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
212219a81c14SSteve Longerbeam 
212319a81c14SSteve Longerbeam 	return 0;
21243cca8ef5SHugues Fruchet 
21253cca8ef5SHugues Fruchet restore_auto_exp_gain:
21263cca8ef5SHugues Fruchet 	if (auto_exp)
21273cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
21283cca8ef5SHugues Fruchet restore_auto_gain:
21293cca8ef5SHugues Fruchet 	if (auto_gain)
21303cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
21313cca8ef5SHugues Fruchet 
21323cca8ef5SHugues Fruchet 	return ret;
213319a81c14SSteve Longerbeam }
213419a81c14SSteve Longerbeam 
213519ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
213619ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
213719ad26f9SAkinobu Mita 
213819a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
213919a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
214019a81c14SSteve Longerbeam {
214119a81c14SSteve Longerbeam 	int ret;
214219a81c14SSteve Longerbeam 
214319a81c14SSteve Longerbeam 	/* first load the initial register values */
214419a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
214519a81c14SSteve Longerbeam 	if (ret < 0)
214619a81c14SSteve Longerbeam 		return ret;
2147985cdcb0SHugues Fruchet 	sensor->last_mode = &ov5640_mode_init_data;
214819a81c14SSteve Longerbeam 
21498f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
21507851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
21517851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
21528f57c2f8SMaxime Ripard 	if (ret)
21538f57c2f8SMaxime Ripard 		return ret;
21548f57c2f8SMaxime Ripard 
215519a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2156985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
215719ad26f9SAkinobu Mita 	if (ret < 0)
215819ad26f9SAkinobu Mita 		return ret;
215919ad26f9SAkinobu Mita 
216019ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
216119a81c14SSteve Longerbeam }
216219a81c14SSteve Longerbeam 
216319a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
216419a81c14SSteve Longerbeam {
21651fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
216619a81c14SSteve Longerbeam }
216719a81c14SSteve Longerbeam 
216819a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
216919a81c14SSteve Longerbeam {
217019a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
217119a81c14SSteve Longerbeam 		return;
217219a81c14SSteve Longerbeam 
21731fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
217419a81c14SSteve Longerbeam 
217519a81c14SSteve Longerbeam 	/* camera power cycle */
217619a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
217719a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
217819a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
217919a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
218019a81c14SSteve Longerbeam 
21811fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
218219a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
218319a81c14SSteve Longerbeam 
21841fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
21851d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
218619a81c14SSteve Longerbeam }
218719a81c14SSteve Longerbeam 
21880f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
218919a81c14SSteve Longerbeam {
21900f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
21910f7acb52SHugues Fruchet 	int ret;
219219a81c14SSteve Longerbeam 
21930f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
21940f7acb52SHugues Fruchet 	if (ret) {
21950f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
21960f7acb52SHugues Fruchet 			__func__);
21970f7acb52SHugues Fruchet 		return ret;
21980f7acb52SHugues Fruchet 	}
219919a81c14SSteve Longerbeam 
220019a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
220119a81c14SSteve Longerbeam 				    sensor->supplies);
22020f7acb52SHugues Fruchet 	if (ret) {
22030f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
22040f7acb52SHugues Fruchet 			__func__);
220519a81c14SSteve Longerbeam 		goto xclk_off;
22060f7acb52SHugues Fruchet 	}
220719a81c14SSteve Longerbeam 
220819a81c14SSteve Longerbeam 	ov5640_reset(sensor);
220919a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
221019a81c14SSteve Longerbeam 
221119a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
221219a81c14SSteve Longerbeam 	if (ret)
221319a81c14SSteve Longerbeam 		goto power_off;
221419a81c14SSteve Longerbeam 
22150f7acb52SHugues Fruchet 	return 0;
22160f7acb52SHugues Fruchet 
22170f7acb52SHugues Fruchet power_off:
22180f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
22190f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
22200f7acb52SHugues Fruchet xclk_off:
22210f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
22220f7acb52SHugues Fruchet 	return ret;
22230f7acb52SHugues Fruchet }
22240f7acb52SHugues Fruchet 
22250f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
22260f7acb52SHugues Fruchet {
22270f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
22280f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
22290f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
22300f7acb52SHugues Fruchet }
22310f7acb52SHugues Fruchet 
2232b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2233b1751ae6SLad Prabhakar {
2234b1751ae6SLad Prabhakar 	int ret;
2235b1751ae6SLad Prabhakar 
2236b1751ae6SLad Prabhakar 	if (!on) {
2237b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2238b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2239b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2240b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2241b1751ae6SLad Prabhakar 		return 0;
2242b1751ae6SLad Prabhakar 	}
2243b1751ae6SLad Prabhakar 
2244b1751ae6SLad Prabhakar 	/*
2245b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2246b1751ae6SLad Prabhakar 	 *
2247b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2248b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2249b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2250b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2251b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2252b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2253b1751ae6SLad Prabhakar 	 */
2254b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2255b1751ae6SLad Prabhakar 	if (ret)
2256b1751ae6SLad Prabhakar 		return ret;
2257b1751ae6SLad Prabhakar 
2258b1751ae6SLad Prabhakar 	/*
2259b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2260b1751ae6SLad Prabhakar 	 *
2261b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2262b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2263b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2264b1751ae6SLad Prabhakar 	 */
2265b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2266b1751ae6SLad Prabhakar 	if (ret)
2267b1751ae6SLad Prabhakar 		return ret;
2268b1751ae6SLad Prabhakar 
2269b1751ae6SLad Prabhakar 	/*
2270b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2271b1751ae6SLad Prabhakar 	 *
2272b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2273b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2274b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2275b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2276b1751ae6SLad Prabhakar 	 */
2277b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2278b1751ae6SLad Prabhakar 	if (ret)
2279b1751ae6SLad Prabhakar 		return ret;
2280b1751ae6SLad Prabhakar 
2281b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2282b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2283b1751ae6SLad Prabhakar 
2284b1751ae6SLad Prabhakar 	return 0;
2285b1751ae6SLad Prabhakar }
2286b1751ae6SLad Prabhakar 
2287576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2288576f5d4bSLad Prabhakar {
2289311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
229068579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
229168579b32SHugues Fruchet 	u8 polarities = 0;
2292576f5d4bSLad Prabhakar 	int ret;
2293576f5d4bSLad Prabhakar 
2294576f5d4bSLad Prabhakar 	if (!on) {
2295576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
229668579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2297311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2298311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2299576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2300576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2301576f5d4bSLad Prabhakar 		return 0;
2302576f5d4bSLad Prabhakar 	}
2303576f5d4bSLad Prabhakar 
2304576f5d4bSLad Prabhakar 	/*
2305311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2306311a6408SLad Prabhakar 	 *
2307311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2308311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2309311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2310311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2311311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2312311a6408SLad Prabhakar 	 *
2313311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2314311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2315311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2316311a6408SLad Prabhakar 	 * polarity will be as below:
2317311a6408SLad Prabhakar 	 * - VSYNC:	active high
2318311a6408SLad Prabhakar 	 * - HREF:	active low
2319311a6408SLad Prabhakar 	 * - PCLK:	active low
232068579b32SHugues Fruchet 	 *
232168579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2322311a6408SLad Prabhakar 	 */
232368579b32SHugues Fruchet 
232468579b32SHugues Fruchet 	/*
232568579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
232668579b32SHugues Fruchet 	 *
232768579b32SHugues Fruchet 	 * CCIR656 CTRL00
232868579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
232968579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
233068579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
233168579b32SHugues Fruchet 	 * - [5]:	Fixed f value
233268579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
233368579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
233468579b32SHugues Fruchet 	 * - [1]:	Clip data disable
233568579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
233668579b32SHugues Fruchet 	 *
233768579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
233868579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
233968579b32SHugues Fruchet 	 * - CCIR656 mode enable
234068579b32SHugues Fruchet 	 * - auto generation of sync codes
234168579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
234268579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
234368579b32SHugues Fruchet 	 */
234468579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
234568579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
234668579b32SHugues Fruchet 	if (ret)
234768579b32SHugues Fruchet 		return ret;
234868579b32SHugues Fruchet 
2349311a6408SLad Prabhakar 	/*
2350311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2351311a6408SLad Prabhakar 	 *
2352311a6408SLad Prabhakar 	 * POLARITY CTRL0
2353311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2354311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2355311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2356311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2357311a6408SLad Prabhakar 	 *		and 1 is active low...)
2358311a6408SLad Prabhakar 	 */
235968579b32SHugues Fruchet 	if (!bt656) {
2360311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
236168579b32SHugues Fruchet 			polarities |= BIT(1);
2362311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
236368579b32SHugues Fruchet 			polarities |= BIT(0);
236468579b32SHugues Fruchet 	}
236568579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
236668579b32SHugues Fruchet 		polarities |= BIT(5);
2367311a6408SLad Prabhakar 
236868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2369311a6408SLad Prabhakar 	if (ret)
2370311a6408SLad Prabhakar 		return ret;
2371311a6408SLad Prabhakar 
2372311a6408SLad Prabhakar 	/*
237368579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2374311a6408SLad Prabhakar 	 *
2375311a6408SLad Prabhakar 	 * MIPI CONTROL 00
237668579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
237768579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
237868579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2379311a6408SLad Prabhakar 	 */
2380311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2381311a6408SLad Prabhakar 	if (ret)
2382311a6408SLad Prabhakar 		return ret;
2383311a6408SLad Prabhakar 
2384311a6408SLad Prabhakar 	/*
2385576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2386576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2387576f5d4bSLad Prabhakar 	 *
2388576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2389576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2390576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2391576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2392576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2393576f5d4bSLad Prabhakar 	 */
23944039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
239568579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2396576f5d4bSLad Prabhakar 	if (ret)
2397576f5d4bSLad Prabhakar 		return ret;
2398576f5d4bSLad Prabhakar 
2399576f5d4bSLad Prabhakar 	/*
2400576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2401576f5d4bSLad Prabhakar 	 *
2402576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2403576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2404576f5d4bSLad Prabhakar 	 */
2405576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2406576f5d4bSLad Prabhakar }
2407576f5d4bSLad Prabhakar 
24080f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
24090f7acb52SHugues Fruchet {
24100f7acb52SHugues Fruchet 	int ret = 0;
24110f7acb52SHugues Fruchet 
24120f7acb52SHugues Fruchet 	if (on) {
24130f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
24140f7acb52SHugues Fruchet 		if (ret)
24150f7acb52SHugues Fruchet 			return ret;
24160f7acb52SHugues Fruchet 
241719a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
241819a81c14SSteve Longerbeam 		if (ret)
241919a81c14SSteve Longerbeam 			goto power_off;
2420b1751ae6SLad Prabhakar 	}
242119a81c14SSteve Longerbeam 
2422576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2423b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2424576f5d4bSLad Prabhakar 	else
2425576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2426b1751ae6SLad Prabhakar 	if (ret)
2427b1751ae6SLad Prabhakar 		goto power_off;
2428aa4bb8b8SJacopo Mondi 
2429b1751ae6SLad Prabhakar 	if (!on)
2430aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
243119a81c14SSteve Longerbeam 
243219a81c14SSteve Longerbeam 	return 0;
243319a81c14SSteve Longerbeam 
243419a81c14SSteve Longerbeam power_off:
24350f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
243619a81c14SSteve Longerbeam 	return ret;
243719a81c14SSteve Longerbeam }
243819a81c14SSteve Longerbeam 
243919a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
244019a81c14SSteve Longerbeam 
244119a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
244219a81c14SSteve Longerbeam {
244319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
244419a81c14SSteve Longerbeam 	int ret = 0;
244519a81c14SSteve Longerbeam 
244619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
244719a81c14SSteve Longerbeam 
244819a81c14SSteve Longerbeam 	/*
244919a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
245019a81c14SSteve Longerbeam 	 * update the power state.
245119a81c14SSteve Longerbeam 	 */
245219a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
245319a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
245419a81c14SSteve Longerbeam 		if (ret)
245519a81c14SSteve Longerbeam 			goto out;
245619a81c14SSteve Longerbeam 	}
245719a81c14SSteve Longerbeam 
245819a81c14SSteve Longerbeam 	/* Update the power count. */
245919a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
246019a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
246119a81c14SSteve Longerbeam out:
246219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
246319a81c14SSteve Longerbeam 
246419a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
246519a81c14SSteve Longerbeam 		/* restore controls */
246619a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
246719a81c14SSteve Longerbeam 	}
246819a81c14SSteve Longerbeam 
246919a81c14SSteve Longerbeam 	return ret;
247019a81c14SSteve Longerbeam }
247119a81c14SSteve Longerbeam 
247219a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
247319a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
247419a81c14SSteve Longerbeam 				     u32 width, u32 height)
247519a81c14SSteve Longerbeam {
247619a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
24776530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2478f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2479f6cc192fSMaxime Ripard 	int i;
248019a81c14SSteve Longerbeam 
248119a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2482e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
248319a81c14SSteve Longerbeam 
248419a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
248519a81c14SSteve Longerbeam 		fi->denominator = maxfps;
248619a81c14SSteve Longerbeam 		fi->numerator = 1;
2487e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2488e823fb16SMaxime Ripard 		goto find_mode;
248919a81c14SSteve Longerbeam 	}
249019a81c14SSteve Longerbeam 
2491f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2492f6cc192fSMaxime Ripard 			minfps, maxfps);
2493f6cc192fSMaxime Ripard 
2494f6cc192fSMaxime Ripard 	best_fps = minfps;
2495f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2496f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2497f6cc192fSMaxime Ripard 
2498f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2499f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2500f6cc192fSMaxime Ripard 			rate = i;
2501f6cc192fSMaxime Ripard 		}
2502f6cc192fSMaxime Ripard 	}
250319a81c14SSteve Longerbeam 
250419a81c14SSteve Longerbeam 	fi->numerator = 1;
2505f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
250619a81c14SSteve Longerbeam 
2507e823fb16SMaxime Ripard find_mode:
25085a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
25095a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
251019a81c14SSteve Longerbeam }
251119a81c14SSteve Longerbeam 
251219a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
25130d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
251419a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
251519a81c14SSteve Longerbeam {
251619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
251719a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
251819a81c14SSteve Longerbeam 
251919a81c14SSteve Longerbeam 	if (format->pad != 0)
252019a81c14SSteve Longerbeam 		return -EINVAL;
252119a81c14SSteve Longerbeam 
252219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
252319a81c14SSteve Longerbeam 
252419a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
25250d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
252619a81c14SSteve Longerbeam 						 format->pad);
252719a81c14SSteve Longerbeam 	else
252819a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
252919a81c14SSteve Longerbeam 
253019a81c14SSteve Longerbeam 	format->format = *fmt;
253119a81c14SSteve Longerbeam 
253219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
253319a81c14SSteve Longerbeam 
253419a81c14SSteve Longerbeam 	return 0;
253519a81c14SSteve Longerbeam }
253619a81c14SSteve Longerbeam 
253719a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
253819a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
253919a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
254019a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
254119a81c14SSteve Longerbeam {
254219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
254319a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2544e3ee691dSHugues Fruchet 	int i;
254519a81c14SSteve Longerbeam 
254619a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
254719a81c14SSteve Longerbeam 	if (!mode)
254819a81c14SSteve Longerbeam 		return -EINVAL;
25493145efcdSJacopo Mondi 	fmt->width = mode->crop.width;
25503145efcdSJacopo Mondi 	fmt->height = mode->crop.height;
255119a81c14SSteve Longerbeam 
255219a81c14SSteve Longerbeam 	if (new_mode)
255319a81c14SSteve Longerbeam 		*new_mode = mode;
2554e3ee691dSHugues Fruchet 
2555e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2556e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2557e3ee691dSHugues Fruchet 			break;
2558e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2559e6441fdeSHugues Fruchet 		i = 0;
2560e6441fdeSHugues Fruchet 
2561e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2562e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2563e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2564e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2565e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2566e3ee691dSHugues Fruchet 
256719a81c14SSteve Longerbeam 	return 0;
256819a81c14SSteve Longerbeam }
256919a81c14SSteve Longerbeam 
25703c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
25713c28588fSJacopo Mondi {
25723c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
25733c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
25743c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
25753c28588fSJacopo Mondi 	unsigned int i = 0;
25763c28588fSJacopo Mondi 	u32 pixel_rate;
25773c28588fSJacopo Mondi 	s64 link_freq;
25783c28588fSJacopo Mondi 	u32 num_lanes;
25793c28588fSJacopo Mondi 	u32 bpp;
25803c28588fSJacopo Mondi 
25813c28588fSJacopo Mondi 	/*
25823c28588fSJacopo Mondi 	 * Update the pixel rate control value.
25833c28588fSJacopo Mondi 	 *
25843c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
25853c28588fSJacopo Mondi 	 */
25863c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
25873c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
25883c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
25893c28588fSJacopo Mondi 
25903c28588fSJacopo Mondi 		return 0;
25913c28588fSJacopo Mondi 	}
25923c28588fSJacopo Mondi 
25933c28588fSJacopo Mondi 	/*
25943c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
25953c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
25963c28588fSJacopo Mondi 	 *
25973c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
25983c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
25993c28588fSJacopo Mondi 	 */
26003c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
26013c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
26023c28588fSJacopo Mondi 	do {
26033c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
26043c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
26053c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
26063c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
26073c28588fSJacopo Mondi 
26083c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
26093c28588fSJacopo Mondi 
26103c28588fSJacopo Mondi 	/*
26113c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
26123c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
26133c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
26143c28588fSJacopo Mondi 	 *
26153c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
26163c28588fSJacopo Mondi 	 * correctly to userspace.
26173c28588fSJacopo Mondi 	 */
26183c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
26193c28588fSJacopo Mondi 		pixel_rate /= 2;
26203c28588fSJacopo Mondi 		link_freq /= 2;
26213c28588fSJacopo Mondi 	}
26223c28588fSJacopo Mondi 
26233c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
26243c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
26253c28588fSJacopo Mondi 			break;
26263c28588fSJacopo Mondi 	}
26273c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
26283c28588fSJacopo Mondi 
26293c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
26303c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
26313c28588fSJacopo Mondi 
26323c28588fSJacopo Mondi 	return 0;
26333c28588fSJacopo Mondi }
26343c28588fSJacopo Mondi 
263519a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
26360d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
263719a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
263819a81c14SSteve Longerbeam {
263919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
264019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2641e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
264219a81c14SSteve Longerbeam 	int ret;
264319a81c14SSteve Longerbeam 
264419a81c14SSteve Longerbeam 	if (format->pad != 0)
264519a81c14SSteve Longerbeam 		return -EINVAL;
264619a81c14SSteve Longerbeam 
264719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
264819a81c14SSteve Longerbeam 
264919a81c14SSteve Longerbeam 	if (sensor->streaming) {
265019a81c14SSteve Longerbeam 		ret = -EBUSY;
265119a81c14SSteve Longerbeam 		goto out;
265219a81c14SSteve Longerbeam 	}
265319a81c14SSteve Longerbeam 
2654e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
265519a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
265619a81c14SSteve Longerbeam 	if (ret)
265719a81c14SSteve Longerbeam 		goto out;
265819a81c14SSteve Longerbeam 
2659e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2660e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2661e738f5ddSMirela Rabulea 		goto out;
2662e738f5ddSMirela Rabulea 	}
266319a81c14SSteve Longerbeam 
26646949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
266519a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
266619a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
26676949d864SHugues Fruchet 	}
266807115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2669fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
267007115449SJacopo Mondi 
2671e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2672e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2673e738f5ddSMirela Rabulea 
26743c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
26753c28588fSJacopo Mondi 
267619a81c14SSteve Longerbeam out:
267719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
267819a81c14SSteve Longerbeam 	return ret;
267919a81c14SSteve Longerbeam }
268019a81c14SSteve Longerbeam 
2681e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2682e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2683e3ee691dSHugues Fruchet {
2684e3ee691dSHugues Fruchet 	int ret = 0;
2685d47c4126SHugues Fruchet 	bool is_jpeg = false;
2686b7ed3abdSLoic Poulain 	u8 fmt, mux;
2687e3ee691dSHugues Fruchet 
2688e3ee691dSHugues Fruchet 	switch (format->code) {
26891536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2690e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2691e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2692b7ed3abdSLoic Poulain 		fmt = 0x3f;
2693b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2694e3ee691dSHugues Fruchet 		break;
26951536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2696e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2697e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2698b7ed3abdSLoic Poulain 		fmt = 0x30;
2699b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2700e3ee691dSHugues Fruchet 		break;
2701e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2702e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2703b7ed3abdSLoic Poulain 		fmt = 0x6F;
2704b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2705e3ee691dSHugues Fruchet 		break;
2706e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2707e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2708b7ed3abdSLoic Poulain 		fmt = 0x61;
2709b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2710e3ee691dSHugues Fruchet 		break;
2711d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2712d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2713b7ed3abdSLoic Poulain 		fmt = 0x30;
2714b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2715d47c4126SHugues Fruchet 		is_jpeg = true;
2716d47c4126SHugues Fruchet 		break;
2717b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2718b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2719b7ed3abdSLoic Poulain 		fmt = 0x00;
2720b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2721b7ed3abdSLoic Poulain 		break;
2722b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2723b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2724b7ed3abdSLoic Poulain 		fmt = 0x01;
2725b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2726b7ed3abdSLoic Poulain 		break;
2727b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2728b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2729b7ed3abdSLoic Poulain 		fmt = 0x02;
2730b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2731b7ed3abdSLoic Poulain 		break;
2732b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2733b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2734b7ed3abdSLoic Poulain 		fmt = 0x03;
2735b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2736b7ed3abdSLoic Poulain 		break;
2737e3ee691dSHugues Fruchet 	default:
2738e3ee691dSHugues Fruchet 		return -EINVAL;
2739e3ee691dSHugues Fruchet 	}
2740e3ee691dSHugues Fruchet 
2741e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2742b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2743e3ee691dSHugues Fruchet 	if (ret)
2744e3ee691dSHugues Fruchet 		return ret;
2745e3ee691dSHugues Fruchet 
2746e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2747b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2748d47c4126SHugues Fruchet 	if (ret)
2749d47c4126SHugues Fruchet 		return ret;
2750d47c4126SHugues Fruchet 
2751d47c4126SHugues Fruchet 	/*
2752d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2753d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2754d47c4126SHugues Fruchet 	 */
2755d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2756d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2757d47c4126SHugues Fruchet 	if (ret)
2758d47c4126SHugues Fruchet 		return ret;
2759d47c4126SHugues Fruchet 
2760d47c4126SHugues Fruchet 	/*
2761d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2762d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2763d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2764d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2765d47c4126SHugues Fruchet 	 */
2766d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2767d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2768d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2769d47c4126SHugues Fruchet 	if (ret)
2770d47c4126SHugues Fruchet 		return ret;
2771d47c4126SHugues Fruchet 
2772d47c4126SHugues Fruchet 	/*
2773d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2774d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2775d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2776d47c4126SHugues Fruchet 	 */
2777d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2778d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2779d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2780e3ee691dSHugues Fruchet }
278119a81c14SSteve Longerbeam 
278219a81c14SSteve Longerbeam /*
278319a81c14SSteve Longerbeam  * Sensor Controls.
278419a81c14SSteve Longerbeam  */
278519a81c14SSteve Longerbeam 
278619a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
278719a81c14SSteve Longerbeam {
278819a81c14SSteve Longerbeam 	int ret;
278919a81c14SSteve Longerbeam 
279019a81c14SSteve Longerbeam 	if (value) {
279119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
279219a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
279319a81c14SSteve Longerbeam 		if (ret)
279419a81c14SSteve Longerbeam 			return ret;
279519a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
279619a81c14SSteve Longerbeam 	} else {
279719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
279819a81c14SSteve Longerbeam 	}
279919a81c14SSteve Longerbeam 
280019a81c14SSteve Longerbeam 	return ret;
280119a81c14SSteve Longerbeam }
280219a81c14SSteve Longerbeam 
280319a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
280419a81c14SSteve Longerbeam {
280519a81c14SSteve Longerbeam 	int ret;
280619a81c14SSteve Longerbeam 
280719a81c14SSteve Longerbeam 	if (value) {
280819a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
280919a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
281019a81c14SSteve Longerbeam 		if (ret)
281119a81c14SSteve Longerbeam 			return ret;
281219a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
281319a81c14SSteve Longerbeam 				       value & 0xff);
281419a81c14SSteve Longerbeam 	} else {
281519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
281619a81c14SSteve Longerbeam 	}
281719a81c14SSteve Longerbeam 
281819a81c14SSteve Longerbeam 	return ret;
281919a81c14SSteve Longerbeam }
282019a81c14SSteve Longerbeam 
282119a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
282219a81c14SSteve Longerbeam {
282319a81c14SSteve Longerbeam 	int ret;
282419a81c14SSteve Longerbeam 
282519a81c14SSteve Longerbeam 	if (value) {
282619a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
282719a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
282819a81c14SSteve Longerbeam 		if (ret)
282919a81c14SSteve Longerbeam 			return ret;
283019a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
283119a81c14SSteve Longerbeam 				       value & 0xff);
283219a81c14SSteve Longerbeam 		if (ret)
283319a81c14SSteve Longerbeam 			return ret;
283419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
283519a81c14SSteve Longerbeam 				       value & 0xff);
283619a81c14SSteve Longerbeam 	} else {
283719a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
283819a81c14SSteve Longerbeam 	}
283919a81c14SSteve Longerbeam 
284019a81c14SSteve Longerbeam 	return ret;
284119a81c14SSteve Longerbeam }
284219a81c14SSteve Longerbeam 
284319a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
284419a81c14SSteve Longerbeam {
284519a81c14SSteve Longerbeam 	int ret;
284619a81c14SSteve Longerbeam 
284719a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
284819a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
284919a81c14SSteve Longerbeam 	if (ret)
285019a81c14SSteve Longerbeam 		return ret;
285119a81c14SSteve Longerbeam 
285219a81c14SSteve Longerbeam 	if (!awb) {
285319a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
285419a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
285519a81c14SSteve Longerbeam 
285619a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
285719a81c14SSteve Longerbeam 		if (ret)
285819a81c14SSteve Longerbeam 			return ret;
285919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
286019a81c14SSteve Longerbeam 	}
286119a81c14SSteve Longerbeam 
286219a81c14SSteve Longerbeam 	return ret;
286319a81c14SSteve Longerbeam }
286419a81c14SSteve Longerbeam 
28653cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
28663cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
286719a81c14SSteve Longerbeam {
286819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
28693cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
287019a81c14SSteve Longerbeam 	int ret = 0;
287119a81c14SSteve Longerbeam 
287219a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
28733cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
287419a81c14SSteve Longerbeam 		if (ret)
287519a81c14SSteve Longerbeam 			return ret;
287619a81c14SSteve Longerbeam 	}
287719a81c14SSteve Longerbeam 
28783cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
287919a81c14SSteve Longerbeam 		u16 max_exp;
288019a81c14SSteve Longerbeam 
288119a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
288219a81c14SSteve Longerbeam 					&max_exp);
288319a81c14SSteve Longerbeam 		if (ret)
288419a81c14SSteve Longerbeam 			return ret;
288519a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
288619a81c14SSteve Longerbeam 		if (ret < 0)
288719a81c14SSteve Longerbeam 			return ret;
288819a81c14SSteve Longerbeam 		max_exp += ret;
28896146fde3SHugues Fruchet 		ret = 0;
289019a81c14SSteve Longerbeam 
289119a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
289219a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
289319a81c14SSteve Longerbeam 	}
289419a81c14SSteve Longerbeam 
289519a81c14SSteve Longerbeam 	return ret;
289619a81c14SSteve Longerbeam }
289719a81c14SSteve Longerbeam 
28983cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
289919a81c14SSteve Longerbeam {
290019a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
290119a81c14SSteve Longerbeam 	int ret = 0;
290219a81c14SSteve Longerbeam 
290319a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
29043cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
290519a81c14SSteve Longerbeam 		if (ret)
290619a81c14SSteve Longerbeam 			return ret;
290719a81c14SSteve Longerbeam 	}
290819a81c14SSteve Longerbeam 
29093cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
29103cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
291119a81c14SSteve Longerbeam 
291219a81c14SSteve Longerbeam 	return ret;
291319a81c14SSteve Longerbeam }
291419a81c14SSteve Longerbeam 
29159f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
29169f6d7bacSChen-Yu Tsai 	"Disabled",
29179f6d7bacSChen-Yu Tsai 	"Color bars",
2918bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
2919bddc5cdfSChen-Yu Tsai 	"Color squares",
2920bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
29219f6d7bacSChen-Yu Tsai };
29229f6d7bacSChen-Yu Tsai 
2923a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
2924a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
2925a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
2926a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
2927a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
2928a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
2929a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
2930a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
2931a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
2932a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
2933a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
2934a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
2935a0c29afbSChen-Yu Tsai 
2936a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
2937a0c29afbSChen-Yu Tsai 	0,
29382aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
2939a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
2940bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
2941bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
2942bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
2943bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
2944a0c29afbSChen-Yu Tsai };
2945a0c29afbSChen-Yu Tsai 
294619a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
294719a81c14SSteve Longerbeam {
2948a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
2949a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
295019a81c14SSteve Longerbeam }
295119a81c14SSteve Longerbeam 
29521068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
29531068fecaSMylène Josserand {
29541068fecaSMylène Josserand 	int ret;
29551068fecaSMylène Josserand 
29561068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
29571068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
29581068fecaSMylène Josserand 			     0 : BIT(7));
29591068fecaSMylène Josserand 	if (ret)
29601068fecaSMylène Josserand 		return ret;
29611068fecaSMylène Josserand 
29621068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
29631068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
29641068fecaSMylène Josserand 			      BIT(2) : 0);
29651068fecaSMylène Josserand }
29661068fecaSMylène Josserand 
2967ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
2968ce85705aSHugues Fruchet {
2969ce85705aSHugues Fruchet 	/*
2970c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
2971c3f3ba3eSHugues Fruchet 	 *
2972ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
2973ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
2974ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
2975ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
2976ce85705aSHugues Fruchet 	 */
2977ce85705aSHugues Fruchet 
2978ce85705aSHugues Fruchet 	/*
2979ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2980ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
2981ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
2982ce85705aSHugues Fruchet 	 */
2983ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2984ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
2985c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
2986c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
2987ce85705aSHugues Fruchet }
2988ce85705aSHugues Fruchet 
2989ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
2990ce85705aSHugues Fruchet {
2991c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
2992c3f3ba3eSHugues Fruchet 
2993ce85705aSHugues Fruchet 	/*
2994ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2995ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
2996ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
2997ce85705aSHugues Fruchet 	 */
2998ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2999ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
3000c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
3001c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
3002ce85705aSHugues Fruchet }
3003ce85705aSHugues Fruchet 
300419a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
300519a81c14SSteve Longerbeam {
300619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
300719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
300819a81c14SSteve Longerbeam 	int val;
300919a81c14SSteve Longerbeam 
301019a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
301119a81c14SSteve Longerbeam 
301219a81c14SSteve Longerbeam 	switch (ctrl->id) {
301319a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
301419a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
301519a81c14SSteve Longerbeam 		if (val < 0)
301619a81c14SSteve Longerbeam 			return val;
301719a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
301819a81c14SSteve Longerbeam 		break;
301919a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
302019a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
302119a81c14SSteve Longerbeam 		if (val < 0)
302219a81c14SSteve Longerbeam 			return val;
302319a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
302419a81c14SSteve Longerbeam 		break;
302519a81c14SSteve Longerbeam 	}
302619a81c14SSteve Longerbeam 
302719a81c14SSteve Longerbeam 	return 0;
302819a81c14SSteve Longerbeam }
302919a81c14SSteve Longerbeam 
303019a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
303119a81c14SSteve Longerbeam {
303219a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
303319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
303419a81c14SSteve Longerbeam 	int ret;
303519a81c14SSteve Longerbeam 
303619a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
303719a81c14SSteve Longerbeam 
303819a81c14SSteve Longerbeam 	/*
303919a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
304019a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
304119a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
304219a81c14SSteve Longerbeam 	 */
304319a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
304419a81c14SSteve Longerbeam 		return 0;
304519a81c14SSteve Longerbeam 
304619a81c14SSteve Longerbeam 	switch (ctrl->id) {
304719a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
304819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
304919a81c14SSteve Longerbeam 		break;
305019a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
305119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
305219a81c14SSteve Longerbeam 		break;
305319a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
305419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
305519a81c14SSteve Longerbeam 		break;
305619a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
305719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
305819a81c14SSteve Longerbeam 		break;
305919a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
306019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
306119a81c14SSteve Longerbeam 		break;
306219a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
306319a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
306419a81c14SSteve Longerbeam 		break;
306519a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
306619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
306719a81c14SSteve Longerbeam 		break;
30681068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
30691068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
30701068fecaSMylène Josserand 		break;
3071ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
3072ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
3073ce85705aSHugues Fruchet 		break;
3074ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
3075ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
3076ce85705aSHugues Fruchet 		break;
307719a81c14SSteve Longerbeam 	default:
307819a81c14SSteve Longerbeam 		ret = -EINVAL;
307919a81c14SSteve Longerbeam 		break;
308019a81c14SSteve Longerbeam 	}
308119a81c14SSteve Longerbeam 
308219a81c14SSteve Longerbeam 	return ret;
308319a81c14SSteve Longerbeam }
308419a81c14SSteve Longerbeam 
308519a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
308619a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
308719a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
308819a81c14SSteve Longerbeam };
308919a81c14SSteve Longerbeam 
309019a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
309119a81c14SSteve Longerbeam {
309222845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
309319a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
309419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
309519a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
309619a81c14SSteve Longerbeam 	int ret;
309719a81c14SSteve Longerbeam 
309819a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
309919a81c14SSteve Longerbeam 
310019a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
310119a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
310219a81c14SSteve Longerbeam 
3103cc196e48SBenoit Parrot 	/* Clock related controls */
3104cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
310522845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
310622845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
310722845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
3108cc196e48SBenoit Parrot 
31097a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
31107a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
31117a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
31127a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
31137a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
31147a3b8d4bSJacopo Mondi 
311519a81c14SSteve Longerbeam 	/* Auto/manual white balance */
311619a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
311719a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
311819a81c14SSteve Longerbeam 					   0, 1, 1, 1);
311919a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
312019a81c14SSteve Longerbeam 						0, 4095, 1, 0);
312119a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
312219a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
312319a81c14SSteve Longerbeam 	/* Auto/manual exposure */
312419a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
312519a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
312619a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
312719a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
312819a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
312919a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
313019a81c14SSteve Longerbeam 	/* Auto/manual gain */
313119a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
313219a81c14SSteve Longerbeam 					     0, 1, 1, 1);
313319a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
313419a81c14SSteve Longerbeam 					0, 1023, 1, 0);
313519a81c14SSteve Longerbeam 
313619a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
313719a81c14SSteve Longerbeam 					      0, 255, 1, 64);
313819a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
313919a81c14SSteve Longerbeam 				       0, 359, 1, 0);
314019a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
314119a81c14SSteve Longerbeam 					    0, 255, 1, 0);
314219a81c14SSteve Longerbeam 	ctrls->test_pattern =
314319a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
314419a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
314519a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
3146ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
3147ce85705aSHugues Fruchet 					 0, 1, 1, 0);
3148ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
3149ce85705aSHugues Fruchet 					 0, 1, 1, 0);
315019a81c14SSteve Longerbeam 
31511068fecaSMylène Josserand 	ctrls->light_freq =
31521068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
31531068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
31541068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
31551068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
31561068fecaSMylène Josserand 
315719a81c14SSteve Longerbeam 	if (hdl->error) {
315819a81c14SSteve Longerbeam 		ret = hdl->error;
315919a81c14SSteve Longerbeam 		goto free_ctrls;
316019a81c14SSteve Longerbeam 	}
316119a81c14SSteve Longerbeam 
3162cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
31637a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
316419a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
316519a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
316619a81c14SSteve Longerbeam 
316719a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
316819a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
316919a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
317019a81c14SSteve Longerbeam 
317119a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
317219a81c14SSteve Longerbeam 	return 0;
317319a81c14SSteve Longerbeam 
317419a81c14SSteve Longerbeam free_ctrls:
317519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
317619a81c14SSteve Longerbeam 	return ret;
317719a81c14SSteve Longerbeam }
317819a81c14SSteve Longerbeam 
317919a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
31800d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
318119a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
318219a81c14SSteve Longerbeam {
318319a81c14SSteve Longerbeam 	if (fse->pad != 0)
318419a81c14SSteve Longerbeam 		return -EINVAL;
318519a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
318619a81c14SSteve Longerbeam 		return -EINVAL;
318719a81c14SSteve Longerbeam 
31883145efcdSJacopo Mondi 	fse->min_width = ov5640_mode_data[fse->index].crop.width;
318941d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
31903145efcdSJacopo Mondi 	fse->min_height = ov5640_mode_data[fse->index].crop.height;
319141d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
319219a81c14SSteve Longerbeam 
319319a81c14SSteve Longerbeam 	return 0;
319419a81c14SSteve Longerbeam }
319519a81c14SSteve Longerbeam 
319619a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
319719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
31980d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
319919a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
320019a81c14SSteve Longerbeam {
320119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
320219a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
320319a81c14SSteve Longerbeam 	int ret;
320419a81c14SSteve Longerbeam 
320519a81c14SSteve Longerbeam 	if (fie->pad != 0)
320619a81c14SSteve Longerbeam 		return -EINVAL;
320719a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
320819a81c14SSteve Longerbeam 		return -EINVAL;
320919a81c14SSteve Longerbeam 
321019a81c14SSteve Longerbeam 	tpf.numerator = 1;
321119a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
321219a81c14SSteve Longerbeam 
321319a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
321419a81c14SSteve Longerbeam 					fie->width, fie->height);
321519a81c14SSteve Longerbeam 	if (ret < 0)
321619a81c14SSteve Longerbeam 		return -EINVAL;
321719a81c14SSteve Longerbeam 
321819a81c14SSteve Longerbeam 	fie->interval = tpf;
321919a81c14SSteve Longerbeam 	return 0;
322019a81c14SSteve Longerbeam }
322119a81c14SSteve Longerbeam 
322219a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
322319a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
322419a81c14SSteve Longerbeam {
322519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
322619a81c14SSteve Longerbeam 
322719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
322819a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
322919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
323019a81c14SSteve Longerbeam 
323119a81c14SSteve Longerbeam 	return 0;
323219a81c14SSteve Longerbeam }
323319a81c14SSteve Longerbeam 
323419a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
323519a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
323619a81c14SSteve Longerbeam {
323719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
323819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
323919a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
324019a81c14SSteve Longerbeam 
324119a81c14SSteve Longerbeam 	if (fi->pad != 0)
324219a81c14SSteve Longerbeam 		return -EINVAL;
324319a81c14SSteve Longerbeam 
324419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
324519a81c14SSteve Longerbeam 
324619a81c14SSteve Longerbeam 	if (sensor->streaming) {
324719a81c14SSteve Longerbeam 		ret = -EBUSY;
324819a81c14SSteve Longerbeam 		goto out;
324919a81c14SSteve Longerbeam 	}
325019a81c14SSteve Longerbeam 
325119a81c14SSteve Longerbeam 	mode = sensor->current_mode;
325219a81c14SSteve Longerbeam 
325319a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
32543145efcdSJacopo Mondi 					       mode->crop.width,
32553145efcdSJacopo Mondi 					       mode->crop.height);
3256e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3257e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3258e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3259e823fb16SMaxime Ripard 		goto out;
3260e823fb16SMaxime Ripard 	}
326119a81c14SSteve Longerbeam 
32623145efcdSJacopo Mondi 	mode = ov5640_find_mode(sensor, frame_rate, mode->crop.width,
32633145efcdSJacopo Mondi 				mode->crop.height, true);
32643c4a7372SHugues Fruchet 	if (!mode) {
32653c4a7372SHugues Fruchet 		ret = -EINVAL;
32663c4a7372SHugues Fruchet 		goto out;
32673c4a7372SHugues Fruchet 	}
32683c4a7372SHugues Fruchet 
32690929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
32700929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
32710929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
32720929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
32733c4a7372SHugues Fruchet 		sensor->current_mode = mode;
327419a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3275cc196e48SBenoit Parrot 
3276cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3277cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
32786949d864SHugues Fruchet 	}
327919a81c14SSteve Longerbeam out:
328019a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
328119a81c14SSteve Longerbeam 	return ret;
328219a81c14SSteve Longerbeam }
328319a81c14SSteve Longerbeam 
328419a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
32850d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
328619a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
328719a81c14SSteve Longerbeam {
328819a81c14SSteve Longerbeam 	if (code->pad != 0)
328919a81c14SSteve Longerbeam 		return -EINVAL;
3290e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
329119a81c14SSteve Longerbeam 		return -EINVAL;
329219a81c14SSteve Longerbeam 
3293e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
329419a81c14SSteve Longerbeam 	return 0;
329519a81c14SSteve Longerbeam }
329619a81c14SSteve Longerbeam 
329719a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
329819a81c14SSteve Longerbeam {
329919a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
330019a81c14SSteve Longerbeam 	int ret = 0;
330119a81c14SSteve Longerbeam 
330219a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
330319a81c14SSteve Longerbeam 
330419a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
330519a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3306985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
330719a81c14SSteve Longerbeam 			if (ret)
330819a81c14SSteve Longerbeam 				goto out;
3309fb98e29fSHugues Fruchet 		}
3310e3ee691dSHugues Fruchet 
3311fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3312e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3313e3ee691dSHugues Fruchet 			if (ret)
3314e3ee691dSHugues Fruchet 				goto out;
3315fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
331619a81c14SSteve Longerbeam 		}
331719a81c14SSteve Longerbeam 
33188e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3319f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3320f22996dbSHugues Fruchet 		else
3321f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3322f22996dbSHugues Fruchet 
332319a81c14SSteve Longerbeam 		if (!ret)
332419a81c14SSteve Longerbeam 			sensor->streaming = enable;
332519a81c14SSteve Longerbeam 	}
332619a81c14SSteve Longerbeam out:
332719a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
332819a81c14SSteve Longerbeam 	return ret;
332919a81c14SSteve Longerbeam }
333019a81c14SSteve Longerbeam 
333119a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
333219a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
33332d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
33342d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
33352d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
333619a81c14SSteve Longerbeam };
333719a81c14SSteve Longerbeam 
333819a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
333919a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
334019a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
334119a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
334219a81c14SSteve Longerbeam };
334319a81c14SSteve Longerbeam 
334419a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
334519a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
334619a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
334719a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
334819a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
334919a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
335019a81c14SSteve Longerbeam };
335119a81c14SSteve Longerbeam 
335219a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
335319a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
335419a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
335519a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
335619a81c14SSteve Longerbeam };
335719a81c14SSteve Longerbeam 
335819a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
335919a81c14SSteve Longerbeam {
336019a81c14SSteve Longerbeam 	int i;
336119a81c14SSteve Longerbeam 
336219a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
336319a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
336419a81c14SSteve Longerbeam 
336519a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
336619a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
336719a81c14SSteve Longerbeam 				       sensor->supplies);
336819a81c14SSteve Longerbeam }
336919a81c14SSteve Longerbeam 
33700f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
33710f7acb52SHugues Fruchet {
33720f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
33730f7acb52SHugues Fruchet 	int ret = 0;
33740f7acb52SHugues Fruchet 	u16 chip_id;
33750f7acb52SHugues Fruchet 
33760f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
33770f7acb52SHugues Fruchet 	if (ret)
33780f7acb52SHugues Fruchet 		return ret;
33790f7acb52SHugues Fruchet 
33800f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
33810f7acb52SHugues Fruchet 	if (ret) {
33820f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
33830f7acb52SHugues Fruchet 			__func__);
33840f7acb52SHugues Fruchet 		goto power_off;
33850f7acb52SHugues Fruchet 	}
33860f7acb52SHugues Fruchet 
33870f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
33880f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
33890f7acb52SHugues Fruchet 			__func__, chip_id);
33900f7acb52SHugues Fruchet 		ret = -ENXIO;
33910f7acb52SHugues Fruchet 	}
33920f7acb52SHugues Fruchet 
33930f7acb52SHugues Fruchet power_off:
33940f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
33950f7acb52SHugues Fruchet 	return ret;
33960f7acb52SHugues Fruchet }
33970f7acb52SHugues Fruchet 
3398e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
339919a81c14SSteve Longerbeam {
340019a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
340119a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
340219a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3403e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3404c3f3ba3eSHugues Fruchet 	u32 rotation;
340519a81c14SSteve Longerbeam 	int ret;
340619a81c14SSteve Longerbeam 
340719a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
340819a81c14SSteve Longerbeam 	if (!sensor)
340919a81c14SSteve Longerbeam 		return -ENOMEM;
341019a81c14SSteve Longerbeam 
341119a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3412fb98e29fSHugues Fruchet 
3413fb98e29fSHugues Fruchet 	/*
3414fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3415fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3416fb98e29fSHugues Fruchet 	 */
3417e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3418fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3419fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3420e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3421e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3422e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3423e6441fdeSHugues Fruchet 	fmt->width = 640;
3424e6441fdeSHugues Fruchet 	fmt->height = 480;
3425e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
342619a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
342719a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
342819a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
342919a81c14SSteve Longerbeam 	sensor->current_mode =
3430086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3431985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
34323c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
343319a81c14SSteve Longerbeam 
343419a81c14SSteve Longerbeam 	sensor->ae_target = 52;
343519a81c14SSteve Longerbeam 
3436c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3437c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3438c3f3ba3eSHugues Fruchet 				       &rotation);
3439c3f3ba3eSHugues Fruchet 	if (!ret) {
3440c3f3ba3eSHugues Fruchet 		switch (rotation) {
3441c3f3ba3eSHugues Fruchet 		case 180:
3442c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
34431771e9fbSGustavo A. R. Silva 			fallthrough;
3444c3f3ba3eSHugues Fruchet 		case 0:
3445c3f3ba3eSHugues Fruchet 			break;
3446c3f3ba3eSHugues Fruchet 		default:
3447c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3448c3f3ba3eSHugues Fruchet 				 rotation);
3449c3f3ba3eSHugues Fruchet 		}
3450c3f3ba3eSHugues Fruchet 	}
3451c3f3ba3eSHugues Fruchet 
3452ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3453ce96bcf5SSakari Ailus 						  NULL);
345419a81c14SSteve Longerbeam 	if (!endpoint) {
345519a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
345619a81c14SSteve Longerbeam 		return -EINVAL;
345719a81c14SSteve Longerbeam 	}
345819a81c14SSteve Longerbeam 
345919a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
346019a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
346119a81c14SSteve Longerbeam 	if (ret) {
346219a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
346319a81c14SSteve Longerbeam 		return ret;
346419a81c14SSteve Longerbeam 	}
346519a81c14SSteve Longerbeam 
34662c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
34672c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
34682c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
34692c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
34702c61e48dSLad Prabhakar 		return -EINVAL;
34712c61e48dSLad Prabhakar 	}
34722c61e48dSLad Prabhakar 
347319a81c14SSteve Longerbeam 	/* get system clock (xclk) */
347419a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
347519a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
347619a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
347719a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
347819a81c14SSteve Longerbeam 	}
347919a81c14SSteve Longerbeam 
348019a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
348119a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
348219a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
348319a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
348419a81c14SSteve Longerbeam 			sensor->xclk_freq);
348519a81c14SSteve Longerbeam 		return -EINVAL;
348619a81c14SSteve Longerbeam 	}
348719a81c14SSteve Longerbeam 
348819a81c14SSteve Longerbeam 	/* request optional power down pin */
348919a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
349019a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
34918791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
34928791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
34938791a102SFabio Estevam 
349419a81c14SSteve Longerbeam 	/* request optional reset pin */
349519a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
349619a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
34978791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
34988791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
349919a81c14SSteve Longerbeam 
350019a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
350119a81c14SSteve Longerbeam 
35022d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
35032d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
350419a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
350519a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
350619a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
350719a81c14SSteve Longerbeam 	if (ret)
350819a81c14SSteve Longerbeam 		return ret;
350919a81c14SSteve Longerbeam 
351019a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
351119a81c14SSteve Longerbeam 	if (ret)
351219a81c14SSteve Longerbeam 		return ret;
351319a81c14SSteve Longerbeam 
351419a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
351519a81c14SSteve Longerbeam 
35160f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
35170f7acb52SHugues Fruchet 	if (ret)
35180f7acb52SHugues Fruchet 		goto entity_cleanup;
35190f7acb52SHugues Fruchet 
352019a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
352119a81c14SSteve Longerbeam 	if (ret)
352219a81c14SSteve Longerbeam 		goto entity_cleanup;
352319a81c14SSteve Longerbeam 
352415786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
352519a81c14SSteve Longerbeam 	if (ret)
352619a81c14SSteve Longerbeam 		goto free_ctrls;
352719a81c14SSteve Longerbeam 
352819a81c14SSteve Longerbeam 	return 0;
352919a81c14SSteve Longerbeam 
353019a81c14SSteve Longerbeam free_ctrls:
353119a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
353219a81c14SSteve Longerbeam entity_cleanup:
353319a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3534bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
353519a81c14SSteve Longerbeam 	return ret;
353619a81c14SSteve Longerbeam }
353719a81c14SSteve Longerbeam 
353819a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
353919a81c14SSteve Longerbeam {
354019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
354119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
354219a81c14SSteve Longerbeam 
354319a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
354419a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
354519a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3546bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
354719a81c14SSteve Longerbeam 
354819a81c14SSteve Longerbeam 	return 0;
354919a81c14SSteve Longerbeam }
355019a81c14SSteve Longerbeam 
355119a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
355219a81c14SSteve Longerbeam 	{"ov5640", 0},
355319a81c14SSteve Longerbeam 	{},
355419a81c14SSteve Longerbeam };
355519a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
355619a81c14SSteve Longerbeam 
355719a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
355819a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
355919a81c14SSteve Longerbeam 	{ /* sentinel */ }
356019a81c14SSteve Longerbeam };
356119a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
356219a81c14SSteve Longerbeam 
356319a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
356419a81c14SSteve Longerbeam 	.driver = {
356519a81c14SSteve Longerbeam 		.name  = "ov5640",
356619a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
356719a81c14SSteve Longerbeam 	},
356819a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3569e6714993SKieran Bingham 	.probe_new = ov5640_probe,
357019a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
357119a81c14SSteve Longerbeam };
357219a81c14SSteve Longerbeam 
357319a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
357419a81c14SSteve Longerbeam 
357519a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
357619a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3577