xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision 3c28588f)
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 
34*3c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
35*3c28588fSJacopo 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
6486633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO		0x3808
6586633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO		0x380a
6619a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS		0x380c
6719a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS		0x380e
68ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20	0x3820
6919a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21	0x3821
7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00		0x3a00
7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP		0x3a08
7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP		0x3a0a
7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D		0x3a0d
7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E		0x3a0e
7519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F		0x3a0f
7619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10		0x3a10
7719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11		0x3a11
7819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B		0x3a1b
7919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E		0x3a1e
8019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F		0x3a1f
8119a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00	0x3c00
8219a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01	0x3c01
8319a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C	0x3c0c
8419a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01		0x4202
85e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00	0x4300
867cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE		0x4602
877cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE		0x4604
882b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT	0x4713
894039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00	0x4730
90f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00	0x4740
9119a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00		0x4800
9219a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE		0x4814
93e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
9419a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
9519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
9619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
9719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
9819a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
9919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
10019a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
10119a81c14SSteve Longerbeam 
10219a81c14SSteve Longerbeam enum ov5640_mode_id {
10332ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
10432ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
10519a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
10619a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
10719a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
10819a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
10919a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
11019a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
11119a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
11219a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
11319a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
11419a81c14SSteve Longerbeam };
11519a81c14SSteve Longerbeam 
11619a81c14SSteve Longerbeam enum ov5640_frame_rate {
11719a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
11819a81c14SSteve Longerbeam 	OV5640_30_FPS,
119e823fb16SMaxime Ripard 	OV5640_60_FPS,
12019a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
12119a81c14SSteve Longerbeam };
12219a81c14SSteve Longerbeam 
12322845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
12422845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
12522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
12622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
12722845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
12822845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
12922845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
13022845bf2SJacopo Mondi };
13122845bf2SJacopo Mondi 
13222845bf2SJacopo Mondi /*
13322845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
13422845bf2SJacopo Mondi  *
13522845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
13622845bf2SJacopo Mondi  * full resolution mode @15 FPS.
13722845bf2SJacopo Mondi  */
13822845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
13922845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
14022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
14122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
14222845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
14322845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
14422845bf2SJacopo Mondi };
14522845bf2SJacopo Mondi 
1467a3b8d4bSJacopo Mondi /*
1477a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1487a3b8d4bSJacopo Mondi  *
1497a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1507a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1517a3b8d4bSJacopo Mondi  *
1527a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1537a3b8d4bSJacopo Mondi  */
1547a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1557a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1567a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1577a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1587a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1597a3b8d4bSJacopo Mondi };
1607a3b8d4bSJacopo Mondi 
1617a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1627a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1637a3b8d4bSJacopo Mondi 
164b7ed3abdSLoic Poulain enum ov5640_format_mux {
165b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
166b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
167b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
168b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
169b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
170b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
171b7ed3abdSLoic Poulain };
172b7ed3abdSLoic Poulain 
1732d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
174e3ee691dSHugues Fruchet 	u32 code;
175e3ee691dSHugues Fruchet 	u32 colorspace;
1762d7671f6SJacopo Mondi 	u8 bpp;
1772d7671f6SJacopo Mondi } ov5640_formats[] = {
1782d7671f6SJacopo Mondi 	{
1792d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1802d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1812d7671f6SJacopo Mondi 		.bpp = 16,
1822d7671f6SJacopo Mondi 	}, {
1832d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
1842d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1852d7671f6SJacopo Mondi 		.bpp = 16,
1862d7671f6SJacopo Mondi 	}, {
1872d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
1882d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1892d7671f6SJacopo Mondi 		.bpp = 16,
1902d7671f6SJacopo Mondi 	}, {
1912d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
1922d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1932d7671f6SJacopo Mondi 		.bpp = 16,
1942d7671f6SJacopo Mondi 	}, {
1952d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
1962d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1972d7671f6SJacopo Mondi 		.bpp = 16,
1982d7671f6SJacopo Mondi 	}, {
1992d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2002d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2012d7671f6SJacopo Mondi 		.bpp = 16,
2022d7671f6SJacopo Mondi 	}, {
2032d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2042d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2052d7671f6SJacopo Mondi 		.bpp = 16,
2062d7671f6SJacopo Mondi 	}, {
2072d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2082d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2092d7671f6SJacopo Mondi 		.bpp = 8,
2102d7671f6SJacopo Mondi 	}, {
2112d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2122d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2132d7671f6SJacopo Mondi 		.bpp = 8
2142d7671f6SJacopo Mondi 	}, {
2152d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2162d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2172d7671f6SJacopo Mondi 		.bpp = 8,
2182d7671f6SJacopo Mondi 	}, {
2192d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2202d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2212d7671f6SJacopo Mondi 		.bpp = 8,
2222d7671f6SJacopo Mondi 	},
223e3ee691dSHugues Fruchet };
224e3ee691dSHugues Fruchet 
225*3c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
226*3c28588fSJacopo Mondi {
227*3c28588fSJacopo Mondi 	unsigned int i;
228*3c28588fSJacopo Mondi 
229*3c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
230*3c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
231*3c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
232*3c28588fSJacopo Mondi 	}
233*3c28588fSJacopo Mondi 
234*3c28588fSJacopo Mondi 	return 0;
235*3c28588fSJacopo Mondi }
236*3c28588fSJacopo Mondi 
23719a81c14SSteve Longerbeam /*
23819a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
23919a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
24019a81c14SSteve Longerbeam  */
24119a81c14SSteve Longerbeam static unsigned int virtual_channel;
2428670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
24319a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
24419a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
24519a81c14SSteve Longerbeam 
24619a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
24719a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
24819a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
249e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
25019a81c14SSteve Longerbeam };
25119a81c14SSteve Longerbeam 
25219a81c14SSteve Longerbeam /* regulator supplies */
25319a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
25441d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
25519a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
25624c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
25719a81c14SSteve Longerbeam };
25819a81c14SSteve Longerbeam 
25919a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
26019a81c14SSteve Longerbeam 
26119a81c14SSteve Longerbeam /*
26219a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
26319a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
26419a81c14SSteve Longerbeam  */
26519a81c14SSteve Longerbeam enum ov5640_downsize_mode {
26619a81c14SSteve Longerbeam 	SUBSAMPLING,
26719a81c14SSteve Longerbeam 	SCALING,
26819a81c14SSteve Longerbeam };
26919a81c14SSteve Longerbeam 
27019a81c14SSteve Longerbeam struct reg_value {
27119a81c14SSteve Longerbeam 	u16 reg_addr;
27219a81c14SSteve Longerbeam 	u8 val;
27319a81c14SSteve Longerbeam 	u8 mask;
27419a81c14SSteve Longerbeam 	u32 delay_ms;
27519a81c14SSteve Longerbeam };
27619a81c14SSteve Longerbeam 
27719a81c14SSteve Longerbeam struct ov5640_mode_info {
27819a81c14SSteve Longerbeam 	enum ov5640_mode_id id;
27919a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode;
28022845bf2SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
281dba13a0bSMaxime Ripard 	u32 hact;
282476dec01SMaxime Ripard 	u32 htot;
283dba13a0bSMaxime Ripard 	u32 vact;
284476dec01SMaxime Ripard 	u32 vtot;
28519a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
28619a81c14SSteve Longerbeam 	u32 reg_data_size;
2875554c80eSAdam Ford 	u32 max_fps;
28819a81c14SSteve Longerbeam };
28919a81c14SSteve Longerbeam 
29019a81c14SSteve Longerbeam struct ov5640_ctrls {
29119a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
292cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
2937a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
29419a81c14SSteve Longerbeam 	struct {
29519a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
29619a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
29719a81c14SSteve Longerbeam 	};
29819a81c14SSteve Longerbeam 	struct {
29919a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
30019a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
30119a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
30219a81c14SSteve Longerbeam 	};
30319a81c14SSteve Longerbeam 	struct {
30419a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
30519a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
30619a81c14SSteve Longerbeam 	};
30719a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3081068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
30919a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
31019a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
31119a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
31219a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
313ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
314ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
31519a81c14SSteve Longerbeam };
31619a81c14SSteve Longerbeam 
31719a81c14SSteve Longerbeam struct ov5640_dev {
31819a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
31919a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
32019a81c14SSteve Longerbeam 	struct media_pad pad;
32119a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
32219a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
32319a81c14SSteve Longerbeam 	u32 xclk_freq;
32419a81c14SSteve Longerbeam 
32519a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
32619a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
32719a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
328c3f3ba3eSHugues Fruchet 	bool   upside_down;
32919a81c14SSteve Longerbeam 
33019a81c14SSteve Longerbeam 	/* lock to protect all members below */
33119a81c14SSteve Longerbeam 	struct mutex lock;
33219a81c14SSteve Longerbeam 
33319a81c14SSteve Longerbeam 	int power_count;
33419a81c14SSteve Longerbeam 
33519a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
336fb98e29fSHugues Fruchet 	bool pending_fmt_change;
33719a81c14SSteve Longerbeam 
33819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
339985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
34019a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
34119a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
342*3c28588fSJacopo Mondi 	s64 current_link_freq;
34319a81c14SSteve Longerbeam 
34419a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
34519a81c14SSteve Longerbeam 
34619a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
34719a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
34819a81c14SSteve Longerbeam 
34919a81c14SSteve Longerbeam 	bool pending_mode_change;
35019a81c14SSteve Longerbeam 	bool streaming;
35119a81c14SSteve Longerbeam };
35219a81c14SSteve Longerbeam 
35319a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
35419a81c14SSteve Longerbeam {
35519a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
35619a81c14SSteve Longerbeam }
35719a81c14SSteve Longerbeam 
35819a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
35919a81c14SSteve Longerbeam {
36019a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
36119a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
36219a81c14SSteve Longerbeam }
36319a81c14SSteve Longerbeam 
3648e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
3658e823f5cSJacopo Mondi {
3668e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
3678e823f5cSJacopo Mondi }
3688e823f5cSJacopo Mondi 
36919a81c14SSteve Longerbeam /*
37019a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
37119a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
37219a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
37319a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
37419a81c14SSteve Longerbeam  * over i2c.
37519a81c14SSteve Longerbeam  */
376fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
37719a81c14SSteve Longerbeam static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
37819a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
379576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
38019a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
38119a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
38219a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
38319a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
38419a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
38519a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
38619a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
38719a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
38819a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
38919a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
39019a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
39119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
39219a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
39319a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
39419a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
39519a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
396476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
39719a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
39819a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
39919a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
40019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
40119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
40219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
40319a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
40419a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
405aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4062b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
40719a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
408aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
40919a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
41019a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
41119a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
41219a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
41319a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
41419a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
41519a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
41619a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
41719a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
41819a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
41919a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
42019a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
42119a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
42219a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
42319a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
42419a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
42519a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
42619a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
42719a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
42819a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
42919a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
43019a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
43119a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
43219a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
43319a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
43419a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
43519a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
43619a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
43719a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
43819a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
43919a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
44019a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
44119a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
44319a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
44419a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
44519a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
44619a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
44719a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
44819a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
44919a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
45019a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
45119a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
45219a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
45319a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
45519a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
45619a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
45719a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
45819a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
45919a81c14SSteve Longerbeam };
46019a81c14SSteve Longerbeam 
461086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_VGA_640_480[] = {
462c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
46319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
464ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
46519a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
46619a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
46719a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
468476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
46919a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
47019a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
47119a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
47219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
47319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
47419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4752b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
47619a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
47719a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
47819a81c14SSteve Longerbeam };
47919a81c14SSteve Longerbeam 
480086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_XGA_1024_768[] = {
481c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
48219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
483ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
48419a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
48519a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
48619a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
487476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
48819a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 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},
50319a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
50419a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
50519a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
506476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
50719a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
50919a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
51119a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
51219a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5132b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51419a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
51519a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
51619a81c14SSteve Longerbeam };
51719a81c14SSteve Longerbeam 
51832ea5e05SHugues Fruchet static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
51932ea5e05SHugues Fruchet 	{0x3c07, 0x08, 0, 0},
52032ea5e05SHugues Fruchet 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
52132ea5e05SHugues Fruchet 	{0x3814, 0x31, 0, 0},
52232ea5e05SHugues Fruchet 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
52332ea5e05SHugues Fruchet 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
52432ea5e05SHugues Fruchet 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
52532ea5e05SHugues Fruchet 	{0x3810, 0x00, 0, 0},
52632ea5e05SHugues Fruchet 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
52732ea5e05SHugues Fruchet 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
52832ea5e05SHugues Fruchet 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
52932ea5e05SHugues Fruchet 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
53032ea5e05SHugues Fruchet 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
53132ea5e05SHugues Fruchet 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
53232ea5e05SHugues Fruchet 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
53332ea5e05SHugues Fruchet 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
53432ea5e05SHugues Fruchet };
53532ea5e05SHugues Fruchet 
536086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QCIF_176_144[] = {
537c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
53819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
539ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
54019a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
543476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
54419a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5502b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
55119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55219a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
55319a81c14SSteve Longerbeam };
55419a81c14SSteve Longerbeam 
555086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_NTSC_720_480[] = {
556c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
55719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
558ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
55919a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
56019a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
56119a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
562476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
56319a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
56419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
56819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5692b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
57019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57119a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
57219a81c14SSteve Longerbeam };
57319a81c14SSteve Longerbeam 
574086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_PAL_720_576[] = {
575c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
57619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
577ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
57819a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
57919a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
58019a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
581476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
58219a81c14SSteve Longerbeam 	{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
58319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
58419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
58519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
58619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
58719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5882b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
58919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
59019a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
59119a81c14SSteve Longerbeam };
59219a81c14SSteve Longerbeam 
593086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
594c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
59519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
596ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
59719a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
59819a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
59919a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
600476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
60119a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
60219a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
60319a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
60419a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
60519a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
60619a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6072b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
60819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
60919a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
61019a81c14SSteve Longerbeam };
61119a81c14SSteve Longerbeam 
612086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
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},
61619a81c14SSteve Longerbeam 	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
61719a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
61819a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
619476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
62019a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
62119a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
62319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
62419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
62519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6262b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
62719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
628c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
629c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
63019a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
63119a81c14SSteve Longerbeam 	{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
63219a81c14SSteve Longerbeam 	{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
63386633417SMaxime Ripard 	{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
634476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
63519a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
63619a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
63719a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6382b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
63919a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
64092b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
64119a81c14SSteve Longerbeam };
64219a81c14SSteve Longerbeam 
643086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
644c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
64519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
646ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
64719a81c14SSteve Longerbeam 	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
64819a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
64919a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
650476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
65119a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
65219a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
65319a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
65419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
65519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
65619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6572b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
65819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
65919a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
66019a81c14SSteve Longerbeam };
66119a81c14SSteve Longerbeam 
66219a81c14SSteve Longerbeam /* power-on sensor init reg table */
66319a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = {
66422845bf2SJacopo Mondi 	0, SUBSAMPLING,
66522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
66622845bf2SJacopo Mondi 	640, 1896, 480, 984,
667476dec01SMaxime Ripard 	ov5640_init_setting_30fps_VGA,
66819a81c14SSteve Longerbeam 	ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
6695554c80eSAdam Ford 	OV5640_30_FPS,
67019a81c14SSteve Longerbeam };
67119a81c14SSteve Longerbeam 
67219a81c14SSteve Longerbeam static const struct ov5640_mode_info
673086c25f8SMaxime Ripard ov5640_mode_data[OV5640_NUM_MODES] = {
6748409d017SJacopo Mondi 	{
6758409d017SJacopo Mondi 		/* 160x120 */
6768409d017SJacopo Mondi 		OV5640_MODE_QQVGA_160_120, SUBSAMPLING,
67722845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
67832ea5e05SHugues Fruchet 		160, 1896, 120, 984,
67932ea5e05SHugues Fruchet 		ov5640_setting_QQVGA_160_120,
68032ea5e05SHugues Fruchet 		ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
6818409d017SJacopo Mondi 		OV5640_30_FPS
6828409d017SJacopo Mondi 	}, {
6838409d017SJacopo Mondi 		/* 176x144 */
6848409d017SJacopo Mondi 		OV5640_MODE_QCIF_176_144, SUBSAMPLING,
68522845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
686476dec01SMaxime Ripard 		176, 1896, 144, 984,
687086c25f8SMaxime Ripard 		ov5640_setting_QCIF_176_144,
6885554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_QCIF_176_144),
6898409d017SJacopo Mondi 		OV5640_30_FPS
6908409d017SJacopo Mondi 	}, {
6918409d017SJacopo Mondi 		/* 320x240 */
6928409d017SJacopo Mondi 		OV5640_MODE_QVGA_320_240, SUBSAMPLING,
69322845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
694476dec01SMaxime Ripard 		320, 1896, 240, 984,
695086c25f8SMaxime Ripard 		ov5640_setting_QVGA_320_240,
6965554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_QVGA_320_240),
6978409d017SJacopo Mondi 		OV5640_30_FPS
6988409d017SJacopo Mondi 	}, {
6998409d017SJacopo Mondi 		/* 640x480 */
7008409d017SJacopo Mondi 		OV5640_MODE_VGA_640_480, SUBSAMPLING,
70122845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
702476dec01SMaxime Ripard 		640, 1896, 480, 1080,
703086c25f8SMaxime Ripard 		ov5640_setting_VGA_640_480,
7045554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_VGA_640_480),
7058409d017SJacopo Mondi 		OV5640_60_FPS
7068409d017SJacopo Mondi 	}, {
7078409d017SJacopo Mondi 		/* 720x480 */
7088409d017SJacopo Mondi 		OV5640_MODE_NTSC_720_480, SUBSAMPLING,
70922845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_96M,
710476dec01SMaxime Ripard 		720, 1896, 480, 984,
711086c25f8SMaxime Ripard 		ov5640_setting_NTSC_720_480,
7125554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_NTSC_720_480),
7138409d017SJacopo Mondi 		OV5640_30_FPS
7148409d017SJacopo Mondi 	}, {
7158409d017SJacopo Mondi 		/* 720x576 */
7168409d017SJacopo Mondi 		OV5640_MODE_PAL_720_576, SUBSAMPLING,
71722845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_96M,
718476dec01SMaxime Ripard 		720, 1896, 576, 984,
719086c25f8SMaxime Ripard 		ov5640_setting_PAL_720_576,
7205554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_PAL_720_576),
7218409d017SJacopo Mondi 		OV5640_30_FPS
7228409d017SJacopo Mondi 	}, {
7238409d017SJacopo Mondi 		/* 1024x768 */
7248409d017SJacopo Mondi 		OV5640_MODE_XGA_1024_768, SUBSAMPLING,
72522845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_96M,
726476dec01SMaxime Ripard 		1024, 1896, 768, 1080,
727086c25f8SMaxime Ripard 		ov5640_setting_XGA_1024_768,
7285554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_XGA_1024_768),
7298409d017SJacopo Mondi 		OV5640_30_FPS
7308409d017SJacopo Mondi 	}, {
7318409d017SJacopo Mondi 		/* 1280x720 */
7328409d017SJacopo Mondi 		OV5640_MODE_720P_1280_720, SUBSAMPLING,
73322845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_124M,
734476dec01SMaxime Ripard 		1280, 1892, 720, 740,
735086c25f8SMaxime Ripard 		ov5640_setting_720P_1280_720,
7365554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_720P_1280_720),
7378409d017SJacopo Mondi 		OV5640_30_FPS
7388409d017SJacopo Mondi 	}, {
7398409d017SJacopo Mondi 		/* 1920x1080 */
7408409d017SJacopo Mondi 		OV5640_MODE_1080P_1920_1080, SCALING,
74122845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_148M,
742476dec01SMaxime Ripard 		1920, 2500, 1080, 1120,
743086c25f8SMaxime Ripard 		ov5640_setting_1080P_1920_1080,
7445554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
7458409d017SJacopo Mondi 		OV5640_30_FPS
7468409d017SJacopo Mondi 	}, {
7478409d017SJacopo Mondi 		/* 2592x1944 */
7488409d017SJacopo Mondi 		OV5640_MODE_QSXGA_2592_1944, SCALING,
74922845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_168M,
750476dec01SMaxime Ripard 		2592, 2844, 1944, 1968,
751086c25f8SMaxime Ripard 		ov5640_setting_QSXGA_2592_1944,
7525554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
7538409d017SJacopo Mondi 		OV5640_15_FPS
7548409d017SJacopo Mondi 	},
75519a81c14SSteve Longerbeam };
75619a81c14SSteve Longerbeam 
75719a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
75819a81c14SSteve Longerbeam {
75919a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
76019a81c14SSteve Longerbeam 	struct i2c_msg msg;
76119a81c14SSteve Longerbeam 	u8 buf[3];
76219a81c14SSteve Longerbeam 	int ret;
76319a81c14SSteve Longerbeam 
76419a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
76519a81c14SSteve Longerbeam 		return 0;
76619a81c14SSteve Longerbeam 
76719a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
76819a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
76919a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
77019a81c14SSteve Longerbeam 
77119a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
77219a81c14SSteve Longerbeam 	msg.flags = 0;
77319a81c14SSteve Longerbeam 	msg.buf = buf;
77419a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
77519a81c14SSteve Longerbeam 
77619a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
77719a81c14SSteve Longerbeam 	if (ret < 0) {
77819a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
77919a81c14SSteve Longerbeam 		return ret;
78019a81c14SSteve Longerbeam 	}
78119a81c14SSteve Longerbeam 
78219a81c14SSteve Longerbeam 	return 0;
78319a81c14SSteve Longerbeam }
78419a81c14SSteve Longerbeam 
78519a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
78619a81c14SSteve Longerbeam {
78719a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
78819a81c14SSteve Longerbeam 	struct i2c_msg msg;
78919a81c14SSteve Longerbeam 	u8 buf[3];
79019a81c14SSteve Longerbeam 	int ret;
79119a81c14SSteve Longerbeam 
79219a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
79319a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
79419a81c14SSteve Longerbeam 	buf[2] = val;
79519a81c14SSteve Longerbeam 
79619a81c14SSteve Longerbeam 	msg.addr = client->addr;
79719a81c14SSteve Longerbeam 	msg.flags = client->flags;
79819a81c14SSteve Longerbeam 	msg.buf = buf;
79919a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
80019a81c14SSteve Longerbeam 
80119a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
80219a81c14SSteve Longerbeam 	if (ret < 0) {
8033924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
80419a81c14SSteve Longerbeam 			__func__, reg, val);
80519a81c14SSteve Longerbeam 		return ret;
80619a81c14SSteve Longerbeam 	}
80719a81c14SSteve Longerbeam 
80819a81c14SSteve Longerbeam 	return 0;
80919a81c14SSteve Longerbeam }
81019a81c14SSteve Longerbeam 
81119a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
81219a81c14SSteve Longerbeam {
81319a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
81419a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
81519a81c14SSteve Longerbeam 	u8 buf[2];
81619a81c14SSteve Longerbeam 	int ret;
81719a81c14SSteve Longerbeam 
81819a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
81919a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
82019a81c14SSteve Longerbeam 
82119a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
82219a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
82319a81c14SSteve Longerbeam 	msg[0].buf = buf;
82419a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
82519a81c14SSteve Longerbeam 
82619a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
82719a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
82819a81c14SSteve Longerbeam 	msg[1].buf = buf;
82919a81c14SSteve Longerbeam 	msg[1].len = 1;
83019a81c14SSteve Longerbeam 
83119a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
8323924c623SHugues Fruchet 	if (ret < 0) {
8333924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
8343924c623SHugues Fruchet 			__func__, reg);
83519a81c14SSteve Longerbeam 		return ret;
8363924c623SHugues Fruchet 	}
83719a81c14SSteve Longerbeam 
83819a81c14SSteve Longerbeam 	*val = buf[0];
83919a81c14SSteve Longerbeam 	return 0;
84019a81c14SSteve Longerbeam }
84119a81c14SSteve Longerbeam 
84219a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
84319a81c14SSteve Longerbeam {
84419a81c14SSteve Longerbeam 	u8 hi, lo;
84519a81c14SSteve Longerbeam 	int ret;
84619a81c14SSteve Longerbeam 
84719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
84819a81c14SSteve Longerbeam 	if (ret)
84919a81c14SSteve Longerbeam 		return ret;
85019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
85119a81c14SSteve Longerbeam 	if (ret)
85219a81c14SSteve Longerbeam 		return ret;
85319a81c14SSteve Longerbeam 
85419a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
85519a81c14SSteve Longerbeam 	return 0;
85619a81c14SSteve Longerbeam }
85719a81c14SSteve Longerbeam 
85819a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
85919a81c14SSteve Longerbeam {
86019a81c14SSteve Longerbeam 	int ret;
86119a81c14SSteve Longerbeam 
86219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
86319a81c14SSteve Longerbeam 	if (ret)
86419a81c14SSteve Longerbeam 		return ret;
86519a81c14SSteve Longerbeam 
86619a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
86719a81c14SSteve Longerbeam }
86819a81c14SSteve Longerbeam 
86919a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
87019a81c14SSteve Longerbeam 			  u8 mask, u8 val)
87119a81c14SSteve Longerbeam {
87219a81c14SSteve Longerbeam 	u8 readval;
87319a81c14SSteve Longerbeam 	int ret;
87419a81c14SSteve Longerbeam 
87519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
87619a81c14SSteve Longerbeam 	if (ret)
87719a81c14SSteve Longerbeam 		return ret;
87819a81c14SSteve Longerbeam 
87919a81c14SSteve Longerbeam 	readval &= ~mask;
88019a81c14SSteve Longerbeam 	val &= mask;
88119a81c14SSteve Longerbeam 	val |= readval;
88219a81c14SSteve Longerbeam 
88319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
88419a81c14SSteve Longerbeam }
88519a81c14SSteve Longerbeam 
886aa288248SMaxime Ripard /*
887aa288248SMaxime Ripard  * After trying the various combinations, reading various
888f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
889aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
890aa288248SMaxime Ripard  *
891aa288248SMaxime Ripard  *   +--------------+
892aa288248SMaxime Ripard  *   |  Ext. Clock  |
893aa288248SMaxime Ripard  *   +-+------------+
894aa288248SMaxime Ripard  *     |  +----------+
895aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
896aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
897aa288248SMaxime Ripard  *          |  +--------------+
898aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
899aa288248SMaxime Ripard  *             +-+------------+
900aa288248SMaxime Ripard  *               |  +--------------+
901aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
902aa288248SMaxime Ripard  *               |  +-+------------+
903aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
904aa288248SMaxime Ripard  *               |    +  +-----+
905aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
906aa288248SMaxime Ripard  *               |       +-----+
907aa288248SMaxime Ripard  *               |  +--------------+
908aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
909aa288248SMaxime Ripard  *                  +-+------------+
910aa288248SMaxime Ripard  *                    |  +---------+
9114c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
912aa288248SMaxime Ripard  *                       +-+-------+
913aa288248SMaxime Ripard  *                         |  +-------------+
914aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
915aa288248SMaxime Ripard  *                         |  +-+-----------+
916aa288248SMaxime Ripard  *                         |    +---------------> SCLK
917aa288248SMaxime Ripard  *                         |  +-------------+
918aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
919aa288248SMaxime Ripard  *                         |  +-+-----------+
920aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
921aa288248SMaxime Ripard  *                         |  +-------------+
922aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
923aa288248SMaxime Ripard  *                            ++------------+
924aa288248SMaxime Ripard  *                             +  +-----------+
925aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
926aa288248SMaxime Ripard  *                                +-----+-----+
927aa288248SMaxime Ripard  *                                       +------------> PCLK
928aa288248SMaxime Ripard  *
929aa288248SMaxime Ripard  * This is deviating from the datasheet at least for the register
930aa288248SMaxime Ripard  * 0x3108, since it's said here that the PCLK would be clocked from
931aa288248SMaxime Ripard  * the PLL.
932aa288248SMaxime Ripard  *
933aa288248SMaxime Ripard  * There seems to be also (unverified) constraints:
934aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
935aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
936aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
937aa288248SMaxime Ripard  *
938aa288248SMaxime Ripard  * In the two latter cases, these constraints are met since our
939aa288248SMaxime Ripard  * factors are hardcoded. If we were to change that, we would need to
940aa288248SMaxime Ripard  * take this into account. The only varying parts are the PLL
941aa288248SMaxime Ripard  * multiplier and the system clock divider, which are shared between
942aa288248SMaxime Ripard  * all these clocks so won't cause any issue.
943aa288248SMaxime Ripard  */
944aa288248SMaxime Ripard 
945aa288248SMaxime Ripard /*
946aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
947aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
948aa288248SMaxime Ripard  */
949aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
950aa288248SMaxime Ripard 
951aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
952aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
953aa288248SMaxime Ripard 
954aa288248SMaxime Ripard /*
955aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
956aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
957aa288248SMaxime Ripard  */
958aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
959aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
960aa288248SMaxime Ripard 
961aa288248SMaxime Ripard /*
962aa288248SMaxime Ripard  * Hardcode these values for scaler and non-scaler modes.
963aa288248SMaxime Ripard  * FIXME: to be re-calcualted for 1 data lanes setups
964aa288248SMaxime Ripard  */
965aa288248SMaxime Ripard #define OV5640_MIPI_DIV_PCLK	2
966aa288248SMaxime Ripard #define OV5640_MIPI_DIV_SCLK	1
967aa288248SMaxime Ripard 
968aa288248SMaxime Ripard /*
969aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
970aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
971aa288248SMaxime Ripard  */
972aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
973aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
974aa288248SMaxime Ripard 
975aa288248SMaxime Ripard /*
976aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
977aa288248SMaxime Ripard  */
978aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
979aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
980aa288248SMaxime Ripard 
981aa288248SMaxime Ripard /*
982aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
983aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
984aa288248SMaxime Ripard  */
985aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
986aa288248SMaxime Ripard 
987aa288248SMaxime Ripard /*
988aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
989aa288248SMaxime Ripard  * SCLK 2x.
990aa288248SMaxime Ripard  */
991aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
992aa288248SMaxime Ripard 
993aa288248SMaxime Ripard /*
994aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
995aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
996aa288248SMaxime Ripard  */
997aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
998aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
999aa288248SMaxime Ripard 
1000aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
1001aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
1002aa288248SMaxime Ripard 					    u8 sysdiv)
1003aa288248SMaxime Ripard {
1004aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
1005aa288248SMaxime Ripard 
1006aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
1007aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
1008aa288248SMaxime Ripard 		return 0;
1009aa288248SMaxime Ripard 
1010aa288248SMaxime Ripard 	return sysclk / sysdiv;
1011aa288248SMaxime Ripard }
1012aa288248SMaxime Ripard 
1013aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
1014aa288248SMaxime Ripard 					 unsigned long rate,
1015aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1016aa288248SMaxime Ripard 					 u8 *sysdiv)
1017aa288248SMaxime Ripard {
1018aa288248SMaxime Ripard 	unsigned long best = ~0;
1019aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1020aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1021aa288248SMaxime Ripard 
1022aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1023aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1024aa288248SMaxime Ripard 	     _sysdiv++) {
1025aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1026aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1027aa288248SMaxime Ripard 		     _pll_mult++) {
1028aa288248SMaxime Ripard 			unsigned long _rate;
1029aa288248SMaxime Ripard 
1030aa288248SMaxime Ripard 			/*
1031aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1032aa288248SMaxime Ripard 			 * 127.
1033aa288248SMaxime Ripard 			 */
1034aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1035aa288248SMaxime Ripard 				continue;
1036aa288248SMaxime Ripard 
1037aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1038aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1039aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1040aa288248SMaxime Ripard 
1041aa288248SMaxime Ripard 			/*
1042aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1043aa288248SMaxime Ripard 			 * increase sysdiv.
1044aa288248SMaxime Ripard 			 */
10452e3df204SAdam Ford 			if (!_rate)
1046aa288248SMaxime Ripard 				break;
1047aa288248SMaxime Ripard 
1048aa288248SMaxime Ripard 			/*
1049aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1050aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1051aa288248SMaxime Ripard 			 */
1052aa288248SMaxime Ripard 			if (_rate < rate)
1053aa288248SMaxime Ripard 				continue;
1054aa288248SMaxime Ripard 
1055aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1056aa288248SMaxime Ripard 				best = _rate;
1057aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1058aa288248SMaxime Ripard 				best_mult = _pll_mult;
1059aa288248SMaxime Ripard 			}
1060aa288248SMaxime Ripard 
1061aa288248SMaxime Ripard 			if (_rate == rate)
1062aa288248SMaxime Ripard 				goto out;
1063aa288248SMaxime Ripard 		}
1064aa288248SMaxime Ripard 	}
1065aa288248SMaxime Ripard 
1066aa288248SMaxime Ripard out:
1067aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1068aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1069aa288248SMaxime Ripard 	*pll_mult = best_mult;
1070aa288248SMaxime Ripard 
1071aa288248SMaxime Ripard 	return best;
1072aa288248SMaxime Ripard }
1073aa288248SMaxime Ripard 
1074aa288248SMaxime Ripard /*
1075aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1076aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1077aa288248SMaxime Ripard  *
1078aa288248SMaxime Ripard  * @rate: The requested bandwidth per lane in bytes per second.
1079aa288248SMaxime Ripard  *	  'Bandwidth Per Lane' is calculated as:
1080aa288248SMaxime Ripard  *	  bpl = HTOT * VTOT * FPS * bpp / num_lanes;
1081aa288248SMaxime Ripard  *
1082aa288248SMaxime Ripard  * This function use the requested bandwidth to calculate:
1083aa288248SMaxime Ripard  * - sample_rate = bpl / (bpp / num_lanes);
1084aa288248SMaxime Ripard  *	         = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes);
1085aa288248SMaxime Ripard  *
1086aa288248SMaxime Ripard  * - mipi_sclk   = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR)
1087aa288248SMaxime Ripard  *
1088aa288248SMaxime Ripard  * with these fixed parameters:
1089aa288248SMaxime Ripard  *	PLL_RDIV	= 2;
1090aa288248SMaxime Ripard  *	BIT_DIVIDER	= 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
1091aa288248SMaxime Ripard  *	PCLK_DIV	= 1;
1092aa288248SMaxime Ripard  *
1093aa288248SMaxime Ripard  * The MIPI clock generation differs for modes that use the scaler and modes
1094aa288248SMaxime Ripard  * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI
1095aa288248SMaxime Ripard  * BIT CLk, and thus:
1096aa288248SMaxime Ripard  *
1097aa288248SMaxime Ripard  * - mipi_sclk = bpl / MIPI_DIV / 2;
1098aa288248SMaxime Ripard  *   MIPI_DIV = 1;
1099aa288248SMaxime Ripard  *
1100aa288248SMaxime Ripard  * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated
1101aa288248SMaxime Ripard  * from the pixel clock, and thus:
1102aa288248SMaxime Ripard  *
1103aa288248SMaxime Ripard  * - sample_rate = bpl / (bpp / num_lanes);
1104aa288248SMaxime Ripard  *	         = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes);
1105aa288248SMaxime Ripard  *		 = bpl / (4 * MIPI_DIV / num_lanes);
1106aa288248SMaxime Ripard  * - MIPI_DIV	 = bpp / (4 * num_lanes);
1107aa288248SMaxime Ripard  *
1108aa288248SMaxime Ripard  * FIXME: this have been tested with 16bpp and 2 lanes setup only.
1109aa288248SMaxime Ripard  * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
1110aa288248SMaxime Ripard  * above formula for setups with 1 lane or image formats with different bpp.
1111aa288248SMaxime Ripard  *
1112aa288248SMaxime Ripard  * FIXME: this deviates from the sensor manual documentation which is quite
1113aa288248SMaxime Ripard  * thin on the MIPI clock tree generation part.
1114aa288248SMaxime Ripard  */
1115aa288248SMaxime Ripard static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
1116aa288248SMaxime Ripard 				unsigned long rate)
1117aa288248SMaxime Ripard {
1118aa288248SMaxime Ripard 	const struct ov5640_mode_info *mode = sensor->current_mode;
1119aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
1120aa288248SMaxime Ripard 	u8 mipi_div;
1121aa288248SMaxime Ripard 	int ret;
1122aa288248SMaxime Ripard 
1123aa288248SMaxime Ripard 	/*
1124aa288248SMaxime Ripard 	 * 1280x720 is reported to use 'SUBSAMPLING' only,
1125aa288248SMaxime Ripard 	 * but according to the sensor manual it goes through the
1126aa288248SMaxime Ripard 	 * scaler before subsampling.
1127aa288248SMaxime Ripard 	 */
1128aa288248SMaxime Ripard 	if (mode->dn_mode == SCALING ||
1129aa288248SMaxime Ripard 	   (mode->id == OV5640_MODE_720P_1280_720))
1130aa288248SMaxime Ripard 		mipi_div = OV5640_MIPI_DIV_SCLK;
1131aa288248SMaxime Ripard 	else
1132aa288248SMaxime Ripard 		mipi_div = OV5640_MIPI_DIV_PCLK;
1133aa288248SMaxime Ripard 
1134aa288248SMaxime Ripard 	ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv);
1135aa288248SMaxime Ripard 
1136aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1137aa288248SMaxime Ripard 			     0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT);
1138aa288248SMaxime Ripard 
1139aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1140aa288248SMaxime Ripard 			     0xff, sysdiv << 4 | mipi_div);
1141aa288248SMaxime Ripard 	if (ret)
1142aa288248SMaxime Ripard 		return ret;
1143aa288248SMaxime Ripard 
1144aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1145aa288248SMaxime Ripard 	if (ret)
1146aa288248SMaxime Ripard 		return ret;
1147aa288248SMaxime Ripard 
1148aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1149aa288248SMaxime Ripard 			     0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv);
1150aa288248SMaxime Ripard 	if (ret)
1151aa288248SMaxime Ripard 		return ret;
1152aa288248SMaxime Ripard 
1153aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
1154aa288248SMaxime Ripard 			      0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS);
1155aa288248SMaxime Ripard }
1156aa288248SMaxime Ripard 
1157aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1158aa288248SMaxime Ripard 				      unsigned long rate,
1159aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1160aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1161aa288248SMaxime Ripard {
1162aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1163aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1164aa288248SMaxime Ripard 
1165aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1166aa288248SMaxime Ripard 				    sysdiv);
1167aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1168aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1169aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1170aa288248SMaxime Ripard 
1171aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1172aa288248SMaxime Ripard }
1173aa288248SMaxime Ripard 
1174aa288248SMaxime Ripard static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
1175aa288248SMaxime Ripard {
1176aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
1177aa288248SMaxime Ripard 	int ret;
1178aa288248SMaxime Ripard 
1179aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1180aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1181aa288248SMaxime Ripard 
1182aa288248SMaxime Ripard 	if (bit_div == 2)
1183aa288248SMaxime Ripard 		bit_div = 8;
1184aa288248SMaxime Ripard 
1185aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1186aa288248SMaxime Ripard 			     0x0f, bit_div);
1187aa288248SMaxime Ripard 	if (ret)
1188aa288248SMaxime Ripard 		return ret;
1189aa288248SMaxime Ripard 
1190aa288248SMaxime Ripard 	/*
1191aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1192aa288248SMaxime Ripard 	 * the MIPI divider.
1193aa288248SMaxime Ripard 	 */
1194aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1195aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1196aa288248SMaxime Ripard 	if (ret)
1197aa288248SMaxime Ripard 		return ret;
1198aa288248SMaxime Ripard 
1199aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1200aa288248SMaxime Ripard 			     0xff, mult);
1201aa288248SMaxime Ripard 	if (ret)
1202aa288248SMaxime Ripard 		return ret;
1203aa288248SMaxime Ripard 
1204aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1205aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1206aa288248SMaxime Ripard 	if (ret)
1207aa288248SMaxime Ripard 		return ret;
1208aa288248SMaxime Ripard 
1209aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1210aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1211aa288248SMaxime Ripard }
1212aa288248SMaxime Ripard 
12137cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
12147cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
12157cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
12167cb013b1SChen-Yu Tsai {
12177cb013b1SChen-Yu Tsai 	int ret;
12187cb013b1SChen-Yu Tsai 
12192b5c18f9SChen-Yu Tsai 	/*
12202b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
12212b5c18f9SChen-Yu Tsai 	 *
12222b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
12232b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
12242b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
12252b5c18f9SChen-Yu Tsai 	 */
12262b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
12272b5c18f9SChen-Yu Tsai 	if (ret < 0)
12282b5c18f9SChen-Yu Tsai 		return ret;
12292b5c18f9SChen-Yu Tsai 
12307cb013b1SChen-Yu Tsai 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact);
12317cb013b1SChen-Yu Tsai 	if (ret < 0)
12327cb013b1SChen-Yu Tsai 		return ret;
12337cb013b1SChen-Yu Tsai 
12347cb013b1SChen-Yu Tsai 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact);
12357cb013b1SChen-Yu Tsai }
12367cb013b1SChen-Yu Tsai 
123719a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1238bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1239bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1240bad1774eSJacopo Mondi {
1241bad1774eSJacopo Mondi 	int ret;
1242bad1774eSJacopo Mondi 
12437cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
12447cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
12457cb013b1SChen-Yu Tsai 		if (ret < 0)
12467cb013b1SChen-Yu Tsai 			return ret;
12477cb013b1SChen-Yu Tsai 	}
12487cb013b1SChen-Yu Tsai 
1249bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
1250bad1774eSJacopo Mondi 	if (ret < 0)
1251bad1774eSJacopo Mondi 		return ret;
1252bad1774eSJacopo Mondi 
1253bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
1254bad1774eSJacopo Mondi 	if (ret < 0)
1255bad1774eSJacopo Mondi 		return ret;
1256bad1774eSJacopo Mondi 
1257bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
1258bad1774eSJacopo Mondi 	if (ret < 0)
1259bad1774eSJacopo Mondi 		return ret;
1260bad1774eSJacopo Mondi 
1261bad1774eSJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
1262bad1774eSJacopo Mondi }
1263bad1774eSJacopo Mondi 
126419a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor,
126519a81c14SSteve Longerbeam 			    const struct ov5640_mode_info *mode)
126619a81c14SSteve Longerbeam {
126719a81c14SSteve Longerbeam 	const struct reg_value *regs = mode->reg_data;
126819a81c14SSteve Longerbeam 	unsigned int i;
126919a81c14SSteve Longerbeam 	u32 delay_ms;
127019a81c14SSteve Longerbeam 	u16 reg_addr;
127119a81c14SSteve Longerbeam 	u8 mask, val;
127219a81c14SSteve Longerbeam 	int ret = 0;
127319a81c14SSteve Longerbeam 
127419a81c14SSteve Longerbeam 	for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
127519a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
127619a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
127719a81c14SSteve Longerbeam 		val = regs->val;
127819a81c14SSteve Longerbeam 		mask = regs->mask;
127919a81c14SSteve Longerbeam 
12803b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
12813b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
12823b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
12838e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
12843b987d70SLad Prabhakar 			continue;
12853b987d70SLad Prabhakar 
128619a81c14SSteve Longerbeam 		if (mask)
128719a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
128819a81c14SSteve Longerbeam 		else
128919a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
129019a81c14SSteve Longerbeam 		if (ret)
129119a81c14SSteve Longerbeam 			break;
129219a81c14SSteve Longerbeam 
129319a81c14SSteve Longerbeam 		if (delay_ms)
129419a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
129519a81c14SSteve Longerbeam 	}
129619a81c14SSteve Longerbeam 
1297bad1774eSJacopo Mondi 	return ov5640_set_timings(sensor, mode);
129819a81c14SSteve Longerbeam }
129919a81c14SSteve Longerbeam 
1300dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1301dc29a1c1SHugues Fruchet {
1302dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1303dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1304dc29a1c1SHugues Fruchet }
1305dc29a1c1SHugues Fruchet 
130619a81c14SSteve Longerbeam /* read exposure, in number of line periods */
130719a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
130819a81c14SSteve Longerbeam {
130919a81c14SSteve Longerbeam 	int exp, ret;
131019a81c14SSteve Longerbeam 	u8 temp;
131119a81c14SSteve Longerbeam 
131219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
131319a81c14SSteve Longerbeam 	if (ret)
131419a81c14SSteve Longerbeam 		return ret;
131519a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
131619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
131719a81c14SSteve Longerbeam 	if (ret)
131819a81c14SSteve Longerbeam 		return ret;
131919a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
132019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
132119a81c14SSteve Longerbeam 	if (ret)
132219a81c14SSteve Longerbeam 		return ret;
132319a81c14SSteve Longerbeam 	exp |= (int)temp;
132419a81c14SSteve Longerbeam 
132519a81c14SSteve Longerbeam 	return exp >> 4;
132619a81c14SSteve Longerbeam }
132719a81c14SSteve Longerbeam 
132819a81c14SSteve Longerbeam /* write exposure, given number of line periods */
132919a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
133019a81c14SSteve Longerbeam {
133119a81c14SSteve Longerbeam 	int ret;
133219a81c14SSteve Longerbeam 
133319a81c14SSteve Longerbeam 	exposure <<= 4;
133419a81c14SSteve Longerbeam 
133519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
133619a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
133719a81c14SSteve Longerbeam 			       exposure & 0xff);
133819a81c14SSteve Longerbeam 	if (ret)
133919a81c14SSteve Longerbeam 		return ret;
134019a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
134119a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
134219a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
134319a81c14SSteve Longerbeam 	if (ret)
134419a81c14SSteve Longerbeam 		return ret;
134519a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
134619a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
134719a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
134819a81c14SSteve Longerbeam }
134919a81c14SSteve Longerbeam 
135019a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
135119a81c14SSteve Longerbeam {
135219a81c14SSteve Longerbeam 	u16 gain;
135319a81c14SSteve Longerbeam 	int ret;
135419a81c14SSteve Longerbeam 
135519a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
135619a81c14SSteve Longerbeam 	if (ret)
135719a81c14SSteve Longerbeam 		return ret;
135819a81c14SSteve Longerbeam 
135919a81c14SSteve Longerbeam 	return gain & 0x3ff;
136019a81c14SSteve Longerbeam }
136119a81c14SSteve Longerbeam 
13623cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
13633cca8ef5SHugues Fruchet {
13643cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
13653cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
13663cca8ef5SHugues Fruchet }
13673cca8ef5SHugues Fruchet 
13683cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
13693cca8ef5SHugues Fruchet {
13703cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
13713cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
13723cca8ef5SHugues Fruchet }
13733cca8ef5SHugues Fruchet 
1374f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1375f22996dbSHugues Fruchet {
13763b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
13773b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
13783b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1379f22996dbSHugues Fruchet }
1380f22996dbSHugues Fruchet 
1381f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
138219a81c14SSteve Longerbeam {
138319a81c14SSteve Longerbeam 	int ret;
138419a81c14SSteve Longerbeam 
1385aa4bb8b8SJacopo Mondi 	/*
1386aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1387aa4bb8b8SJacopo Mondi 	 *
1388aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1389aa4bb8b8SJacopo Mondi 	 *
1390aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1391aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1392aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1393aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1394aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1395aa4bb8b8SJacopo Mondi 	 *
1396aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1397aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1398aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1399aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1400aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1401aa4bb8b8SJacopo Mondi 	 */
1402aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1403aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
140419a81c14SSteve Longerbeam 	if (ret)
140519a81c14SSteve Longerbeam 		return ret;
140619a81c14SSteve Longerbeam 
140719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
140819a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
140919a81c14SSteve Longerbeam }
141019a81c14SSteve Longerbeam 
141119a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
141219a81c14SSteve Longerbeam {
141319a81c14SSteve Longerbeam 	 /* calculate sysclk */
141419a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
141519a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
141619a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
141719a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
141819a81c14SSteve Longerbeam 	u8 temp1, temp2;
141919a81c14SSteve Longerbeam 	int ret;
142019a81c14SSteve Longerbeam 
142119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
142219a81c14SSteve Longerbeam 	if (ret)
142319a81c14SSteve Longerbeam 		return ret;
142419a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
142519a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
142619a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
142719a81c14SSteve Longerbeam 
142819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
142919a81c14SSteve Longerbeam 	if (ret)
143019a81c14SSteve Longerbeam 		return ret;
143119a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
143219a81c14SSteve Longerbeam 	if (sysdiv == 0)
143319a81c14SSteve Longerbeam 		sysdiv = 16;
143419a81c14SSteve Longerbeam 
143519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
143619a81c14SSteve Longerbeam 	if (ret)
143719a81c14SSteve Longerbeam 		return ret;
143819a81c14SSteve Longerbeam 	multiplier = temp1;
143919a81c14SSteve Longerbeam 
144019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
144119a81c14SSteve Longerbeam 	if (ret)
144219a81c14SSteve Longerbeam 		return ret;
144319a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
144419a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
144519a81c14SSteve Longerbeam 
144619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
144719a81c14SSteve Longerbeam 	if (ret)
144819a81c14SSteve Longerbeam 		return ret;
144919a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
145019a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
145119a81c14SSteve Longerbeam 
145219a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
145319a81c14SSteve Longerbeam 		return -EINVAL;
145419a81c14SSteve Longerbeam 
145519a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
145619a81c14SSteve Longerbeam 
145719a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
145819a81c14SSteve Longerbeam 
145919a81c14SSteve Longerbeam 	return sysclk;
146019a81c14SSteve Longerbeam }
146119a81c14SSteve Longerbeam 
146219a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
146319a81c14SSteve Longerbeam {
146419a81c14SSteve Longerbeam 	 /* read HTS from register settings */
146519a81c14SSteve Longerbeam 	u8 mode;
146619a81c14SSteve Longerbeam 	int ret;
146719a81c14SSteve Longerbeam 
146819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
146919a81c14SSteve Longerbeam 	if (ret)
147019a81c14SSteve Longerbeam 		return ret;
147119a81c14SSteve Longerbeam 	mode &= 0xfb;
147219a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
147319a81c14SSteve Longerbeam }
147419a81c14SSteve Longerbeam 
147519a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
147619a81c14SSteve Longerbeam {
147719a81c14SSteve Longerbeam 	/* read HTS from register settings */
147819a81c14SSteve Longerbeam 	u16 hts;
147919a81c14SSteve Longerbeam 	int ret;
148019a81c14SSteve Longerbeam 
148119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
148219a81c14SSteve Longerbeam 	if (ret)
148319a81c14SSteve Longerbeam 		return ret;
148419a81c14SSteve Longerbeam 	return hts;
148519a81c14SSteve Longerbeam }
148619a81c14SSteve Longerbeam 
148719a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
148819a81c14SSteve Longerbeam {
148919a81c14SSteve Longerbeam 	u16 vts;
149019a81c14SSteve Longerbeam 	int ret;
149119a81c14SSteve Longerbeam 
149219a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
149319a81c14SSteve Longerbeam 	if (ret)
149419a81c14SSteve Longerbeam 		return ret;
149519a81c14SSteve Longerbeam 	return vts;
149619a81c14SSteve Longerbeam }
149719a81c14SSteve Longerbeam 
149819a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
149919a81c14SSteve Longerbeam {
150019a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
150119a81c14SSteve Longerbeam }
150219a81c14SSteve Longerbeam 
150319a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
150419a81c14SSteve Longerbeam {
150519a81c14SSteve Longerbeam 	/* get banding filter value */
150619a81c14SSteve Longerbeam 	int ret, light_freq = 0;
150719a81c14SSteve Longerbeam 	u8 temp, temp1;
150819a81c14SSteve Longerbeam 
150919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
151019a81c14SSteve Longerbeam 	if (ret)
151119a81c14SSteve Longerbeam 		return ret;
151219a81c14SSteve Longerbeam 
151319a81c14SSteve Longerbeam 	if (temp & 0x80) {
151419a81c14SSteve Longerbeam 		/* manual */
151519a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
151619a81c14SSteve Longerbeam 				      &temp1);
151719a81c14SSteve Longerbeam 		if (ret)
151819a81c14SSteve Longerbeam 			return ret;
151919a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
152019a81c14SSteve Longerbeam 			/* 50Hz */
152119a81c14SSteve Longerbeam 			light_freq = 50;
152219a81c14SSteve Longerbeam 		} else {
152319a81c14SSteve Longerbeam 			/* 60Hz */
152419a81c14SSteve Longerbeam 			light_freq = 60;
152519a81c14SSteve Longerbeam 		}
152619a81c14SSteve Longerbeam 	} else {
152719a81c14SSteve Longerbeam 		/* auto */
152819a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
152919a81c14SSteve Longerbeam 				      &temp1);
153019a81c14SSteve Longerbeam 		if (ret)
153119a81c14SSteve Longerbeam 			return ret;
153219a81c14SSteve Longerbeam 
153319a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
153419a81c14SSteve Longerbeam 			/* 50Hz */
153519a81c14SSteve Longerbeam 			light_freq = 50;
153619a81c14SSteve Longerbeam 		} else {
153719a81c14SSteve Longerbeam 			/* 60Hz */
153819a81c14SSteve Longerbeam 		}
153919a81c14SSteve Longerbeam 	}
154019a81c14SSteve Longerbeam 
154119a81c14SSteve Longerbeam 	return light_freq;
154219a81c14SSteve Longerbeam }
154319a81c14SSteve Longerbeam 
154419a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
154519a81c14SSteve Longerbeam {
154619a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
154719a81c14SSteve Longerbeam 	int ret;
154819a81c14SSteve Longerbeam 
154919a81c14SSteve Longerbeam 	/* read preview PCLK */
155019a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
155119a81c14SSteve Longerbeam 	if (ret < 0)
155219a81c14SSteve Longerbeam 		return ret;
155319a81c14SSteve Longerbeam 	if (ret == 0)
155419a81c14SSteve Longerbeam 		return -EINVAL;
155519a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
155619a81c14SSteve Longerbeam 	/* read preview HTS */
155719a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
155819a81c14SSteve Longerbeam 	if (ret < 0)
155919a81c14SSteve Longerbeam 		return ret;
156019a81c14SSteve Longerbeam 	if (ret == 0)
156119a81c14SSteve Longerbeam 		return -EINVAL;
156219a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
156319a81c14SSteve Longerbeam 
156419a81c14SSteve Longerbeam 	/* read preview VTS */
156519a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
156619a81c14SSteve Longerbeam 	if (ret < 0)
156719a81c14SSteve Longerbeam 		return ret;
156819a81c14SSteve Longerbeam 	prev_vts = ret;
156919a81c14SSteve Longerbeam 
157019a81c14SSteve Longerbeam 	/* calculate banding filter */
157119a81c14SSteve Longerbeam 	/* 60Hz */
157219a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
157319a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
157419a81c14SSteve Longerbeam 	if (ret)
157519a81c14SSteve Longerbeam 		return ret;
157619a81c14SSteve Longerbeam 	if (!band_step60)
157719a81c14SSteve Longerbeam 		return -EINVAL;
157819a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
157919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
158019a81c14SSteve Longerbeam 	if (ret)
158119a81c14SSteve Longerbeam 		return ret;
158219a81c14SSteve Longerbeam 
158319a81c14SSteve Longerbeam 	/* 50Hz */
158419a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
158519a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
158619a81c14SSteve Longerbeam 	if (ret)
158719a81c14SSteve Longerbeam 		return ret;
158819a81c14SSteve Longerbeam 	if (!band_step50)
158919a81c14SSteve Longerbeam 		return -EINVAL;
159019a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
159119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
159219a81c14SSteve Longerbeam }
159319a81c14SSteve Longerbeam 
159419a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
159519a81c14SSteve Longerbeam {
159619a81c14SSteve Longerbeam 	/* stable in high */
159719a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
159819a81c14SSteve Longerbeam 	int ret;
159919a81c14SSteve Longerbeam 
160019a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
160119a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
160219a81c14SSteve Longerbeam 
160319a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
160419a81c14SSteve Longerbeam 	if (fast_high > 255)
160519a81c14SSteve Longerbeam 		fast_high = 255;
160619a81c14SSteve Longerbeam 
160719a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
160819a81c14SSteve Longerbeam 
160919a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
161019a81c14SSteve Longerbeam 	if (ret)
161119a81c14SSteve Longerbeam 		return ret;
161219a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
161319a81c14SSteve Longerbeam 	if (ret)
161419a81c14SSteve Longerbeam 		return ret;
161519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
161619a81c14SSteve Longerbeam 	if (ret)
161719a81c14SSteve Longerbeam 		return ret;
161819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
161919a81c14SSteve Longerbeam 	if (ret)
162019a81c14SSteve Longerbeam 		return ret;
162119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
162219a81c14SSteve Longerbeam 	if (ret)
162319a81c14SSteve Longerbeam 		return ret;
162419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
162519a81c14SSteve Longerbeam }
162619a81c14SSteve Longerbeam 
1627c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
162819a81c14SSteve Longerbeam {
162919a81c14SSteve Longerbeam 	u8 temp;
163019a81c14SSteve Longerbeam 	int ret;
163119a81c14SSteve Longerbeam 
163219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
163319a81c14SSteve Longerbeam 	if (ret)
163419a81c14SSteve Longerbeam 		return ret;
1635c2c3f42dSHugues Fruchet 
1636c2c3f42dSHugues Fruchet 	return temp & BIT(0);
163719a81c14SSteve Longerbeam }
163819a81c14SSteve Longerbeam 
1639ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1640ce85705aSHugues Fruchet {
1641ce85705aSHugues Fruchet 	int ret;
1642ce85705aSHugues Fruchet 
1643ce85705aSHugues Fruchet 	/*
1644ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1645ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1646ce85705aSHugues Fruchet 	 */
1647ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1648ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1649ce85705aSHugues Fruchet 	if (ret)
1650ce85705aSHugues Fruchet 		return ret;
1651ce85705aSHugues Fruchet 	/*
1652ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1653ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1654ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1655ce85705aSHugues Fruchet 	 */
1656ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1657ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1658ce85705aSHugues Fruchet }
1659ce85705aSHugues Fruchet 
166019a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
166119a81c14SSteve Longerbeam {
16628670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
166319a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
166419a81c14SSteve Longerbeam 	int ret;
166519a81c14SSteve Longerbeam 
16668670d70aSHugues Fruchet 	if (channel > 3) {
16678670d70aSHugues Fruchet 		dev_err(&client->dev,
16688670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
16698670d70aSHugues Fruchet 			__func__, channel);
167019a81c14SSteve Longerbeam 		return -EINVAL;
16718670d70aSHugues Fruchet 	}
167219a81c14SSteve Longerbeam 
167319a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
167419a81c14SSteve Longerbeam 	if (ret)
167519a81c14SSteve Longerbeam 		return ret;
167619a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
167719a81c14SSteve Longerbeam 	temp |= (channel << 6);
167819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
167919a81c14SSteve Longerbeam }
168019a81c14SSteve Longerbeam 
168119a81c14SSteve Longerbeam static const struct ov5640_mode_info *
168219a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
168319a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
168419a81c14SSteve Longerbeam {
16853c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
168619a81c14SSteve Longerbeam 
1687086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
1688086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
16893c4a7372SHugues Fruchet 				      hact, vact,
16903c4a7372SHugues Fruchet 				      width, height);
169119a81c14SSteve Longerbeam 
16923c4a7372SHugues Fruchet 	if (!mode ||
16933c4a7372SHugues Fruchet 	    (!nearest && (mode->hact != width || mode->vact != height)))
16943c4a7372SHugues Fruchet 		return NULL;
169519a81c14SSteve Longerbeam 
16965554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
16975554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
1698981e4454SBenoit Parrot 		return NULL;
1699981e4454SBenoit Parrot 
170019a81c14SSteve Longerbeam 	return mode;
170119a81c14SSteve Longerbeam }
170219a81c14SSteve Longerbeam 
1703cc196e48SBenoit Parrot static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
1704cc196e48SBenoit Parrot {
1705cc196e48SBenoit Parrot 	u64 rate;
1706cc196e48SBenoit Parrot 
1707cc196e48SBenoit Parrot 	rate = sensor->current_mode->vtot * sensor->current_mode->htot;
1708cc196e48SBenoit Parrot 	rate *= ov5640_framerates[sensor->current_fr];
1709cc196e48SBenoit Parrot 
1710cc196e48SBenoit Parrot 	return rate;
1711cc196e48SBenoit Parrot }
1712cc196e48SBenoit Parrot 
171319a81c14SSteve Longerbeam /*
171419a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
171519a81c14SSteve Longerbeam  * exposure calculation
171619a81c14SSteve Longerbeam  */
171741d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
171841d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
171919a81c14SSteve Longerbeam {
172019a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
172119a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
172219a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
172319a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
172419a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
172519a81c14SSteve Longerbeam 	u8 average;
172619a81c14SSteve Longerbeam 	int ret;
172719a81c14SSteve Longerbeam 
172841d8d7f5SHugues Fruchet 	if (!mode->reg_data)
172919a81c14SSteve Longerbeam 		return -EINVAL;
173019a81c14SSteve Longerbeam 
173119a81c14SSteve Longerbeam 	/* read preview shutter */
173219a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
173319a81c14SSteve Longerbeam 	if (ret < 0)
173419a81c14SSteve Longerbeam 		return ret;
173519a81c14SSteve Longerbeam 	prev_shutter = ret;
1736c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
173719a81c14SSteve Longerbeam 	if (ret < 0)
173819a81c14SSteve Longerbeam 		return ret;
173919a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
174019a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
174119a81c14SSteve Longerbeam 		prev_shutter *= 2;
174219a81c14SSteve Longerbeam 
174319a81c14SSteve Longerbeam 	/* read preview gain */
174419a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
174519a81c14SSteve Longerbeam 	if (ret < 0)
174619a81c14SSteve Longerbeam 		return ret;
174719a81c14SSteve Longerbeam 	prev_gain16 = ret;
174819a81c14SSteve Longerbeam 
174919a81c14SSteve Longerbeam 	/* get average */
175019a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
175119a81c14SSteve Longerbeam 	if (ret)
175219a81c14SSteve Longerbeam 		return ret;
175319a81c14SSteve Longerbeam 
175419a81c14SSteve Longerbeam 	/* turn off night mode for capture */
175519a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
175619a81c14SSteve Longerbeam 	if (ret < 0)
175719a81c14SSteve Longerbeam 		return ret;
175819a81c14SSteve Longerbeam 
175919a81c14SSteve Longerbeam 	/* Write capture setting */
176019a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, mode);
176119a81c14SSteve Longerbeam 	if (ret < 0)
176219a81c14SSteve Longerbeam 		return ret;
176319a81c14SSteve Longerbeam 
176419a81c14SSteve Longerbeam 	/* read capture VTS */
176519a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
176619a81c14SSteve Longerbeam 	if (ret < 0)
176719a81c14SSteve Longerbeam 		return ret;
176819a81c14SSteve Longerbeam 	cap_vts = ret;
176919a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
177019a81c14SSteve Longerbeam 	if (ret < 0)
177119a81c14SSteve Longerbeam 		return ret;
177219a81c14SSteve Longerbeam 	if (ret == 0)
177319a81c14SSteve Longerbeam 		return -EINVAL;
177419a81c14SSteve Longerbeam 	cap_hts = ret;
177519a81c14SSteve Longerbeam 
177619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
177719a81c14SSteve Longerbeam 	if (ret < 0)
177819a81c14SSteve Longerbeam 		return ret;
177919a81c14SSteve Longerbeam 	if (ret == 0)
178019a81c14SSteve Longerbeam 		return -EINVAL;
178119a81c14SSteve Longerbeam 	cap_sysclk = ret;
178219a81c14SSteve Longerbeam 
178319a81c14SSteve Longerbeam 	/* calculate capture banding filter */
178419a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
178519a81c14SSteve Longerbeam 	if (ret < 0)
178619a81c14SSteve Longerbeam 		return ret;
178719a81c14SSteve Longerbeam 	light_freq = ret;
178819a81c14SSteve Longerbeam 
178919a81c14SSteve Longerbeam 	if (light_freq == 60) {
179019a81c14SSteve Longerbeam 		/* 60Hz */
179119a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
179219a81c14SSteve Longerbeam 	} else {
179319a81c14SSteve Longerbeam 		/* 50Hz */
179419a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
179519a81c14SSteve Longerbeam 	}
179619a81c14SSteve Longerbeam 
179719a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
179819a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
179919a81c14SSteve Longerbeam 		if (ret < 0)
180019a81c14SSteve Longerbeam 			return ret;
180119a81c14SSteve Longerbeam 		if (ret == 0)
180219a81c14SSteve Longerbeam 			return -EINVAL;
180319a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
180419a81c14SSteve Longerbeam 	}
180519a81c14SSteve Longerbeam 
180619a81c14SSteve Longerbeam 	if (!cap_bandfilt)
180719a81c14SSteve Longerbeam 		return -EINVAL;
180819a81c14SSteve Longerbeam 
180919a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
181019a81c14SSteve Longerbeam 
181119a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
181219a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
181319a81c14SSteve Longerbeam 		/* in stable range */
181419a81c14SSteve Longerbeam 		cap_gain16_shutter =
181519a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
181619a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
181719a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts *
181819a81c14SSteve Longerbeam 			sensor->ae_target / average;
181919a81c14SSteve Longerbeam 	} else {
182019a81c14SSteve Longerbeam 		cap_gain16_shutter =
182119a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
182219a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
182319a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
182419a81c14SSteve Longerbeam 	}
182519a81c14SSteve Longerbeam 
182619a81c14SSteve Longerbeam 	/* gain to shutter */
182719a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
182819a81c14SSteve Longerbeam 		/* shutter < 1/100 */
182919a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
183019a81c14SSteve Longerbeam 		if (cap_shutter < 1)
183119a81c14SSteve Longerbeam 			cap_shutter = 1;
183219a81c14SSteve Longerbeam 
183319a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
183419a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
183519a81c14SSteve Longerbeam 			cap_gain16 = 16;
183619a81c14SSteve Longerbeam 	} else {
183719a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
183819a81c14SSteve Longerbeam 			/* exposure reach max */
183919a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
184019a81c14SSteve Longerbeam 			if (!cap_shutter)
184119a81c14SSteve Longerbeam 				return -EINVAL;
184219a81c14SSteve Longerbeam 
184319a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
184419a81c14SSteve Longerbeam 		} else {
184519a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
184619a81c14SSteve Longerbeam 			cap_shutter =
184719a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
184819a81c14SSteve Longerbeam 				* cap_bandfilt;
184919a81c14SSteve Longerbeam 			if (!cap_shutter)
185019a81c14SSteve Longerbeam 				return -EINVAL;
185119a81c14SSteve Longerbeam 
185219a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
185319a81c14SSteve Longerbeam 		}
185419a81c14SSteve Longerbeam 	}
185519a81c14SSteve Longerbeam 
185619a81c14SSteve Longerbeam 	/* set capture gain */
18573cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
185819a81c14SSteve Longerbeam 	if (ret)
185919a81c14SSteve Longerbeam 		return ret;
186019a81c14SSteve Longerbeam 
186119a81c14SSteve Longerbeam 	/* write capture shutter */
186219a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
186319a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
186419a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
186519a81c14SSteve Longerbeam 		if (ret < 0)
186619a81c14SSteve Longerbeam 			return ret;
186719a81c14SSteve Longerbeam 	}
186819a81c14SSteve Longerbeam 
186919a81c14SSteve Longerbeam 	/* set exposure */
18703cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
187119a81c14SSteve Longerbeam }
187219a81c14SSteve Longerbeam 
187319a81c14SSteve Longerbeam /*
187419a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
187519a81c14SSteve Longerbeam  * change mode directly
187619a81c14SSteve Longerbeam  */
187719a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
18783cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
187919a81c14SSteve Longerbeam {
188041d8d7f5SHugues Fruchet 	if (!mode->reg_data)
188119a81c14SSteve Longerbeam 		return -EINVAL;
188219a81c14SSteve Longerbeam 
188319a81c14SSteve Longerbeam 	/* Write capture setting */
18843cca8ef5SHugues Fruchet 	return ov5640_load_regs(sensor, mode);
188519a81c14SSteve Longerbeam }
188619a81c14SSteve Longerbeam 
1887985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
188819a81c14SSteve Longerbeam {
188919a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
1890985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
189119a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
18923cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
1893dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
1894aa288248SMaxime Ripard 	unsigned long rate;
189519a81c14SSteve Longerbeam 	int ret;
189619a81c14SSteve Longerbeam 
189719a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
189819a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
189919a81c14SSteve Longerbeam 
190019a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
19013cca8ef5SHugues Fruchet 	if (auto_gain) {
19023cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
190319a81c14SSteve Longerbeam 		if (ret)
190419a81c14SSteve Longerbeam 			return ret;
19053cca8ef5SHugues Fruchet 	}
1906bf4a4b51SMaxime Ripard 
19073cca8ef5SHugues Fruchet 	if (auto_exp) {
1908dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
190919a81c14SSteve Longerbeam 		if (ret)
19103cca8ef5SHugues Fruchet 			goto restore_auto_gain;
19113cca8ef5SHugues Fruchet 	}
191219a81c14SSteve Longerbeam 
1913aa288248SMaxime Ripard 	/*
1914aa288248SMaxime Ripard 	 * All the formats we support have 16 bits per pixel, seems to require
1915aa288248SMaxime Ripard 	 * the same rate than YUV, so we can just use 16 bpp all the time.
1916aa288248SMaxime Ripard 	 */
1917cc196e48SBenoit Parrot 	rate = ov5640_calc_pixel_rate(sensor) * 16;
19188e823f5cSJacopo Mondi 	if (ov5640_is_csi2(sensor)) {
1919aa288248SMaxime Ripard 		rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
1920aa288248SMaxime Ripard 		ret = ov5640_set_mipi_pclk(sensor, rate);
1921aa288248SMaxime Ripard 	} else {
1922aa288248SMaxime Ripard 		rate = rate / sensor->ep.bus.parallel.bus_width;
1923aa288248SMaxime Ripard 		ret = ov5640_set_dvp_pclk(sensor, rate);
1924aa288248SMaxime Ripard 	}
1925aa288248SMaxime Ripard 
1926aa288248SMaxime Ripard 	if (ret < 0)
1927aa288248SMaxime Ripard 		return 0;
1928aa288248SMaxime Ripard 
192919a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
193019a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
193119a81c14SSteve Longerbeam 		/*
193219a81c14SSteve Longerbeam 		 * change between subsampling and scaling
19333cca8ef5SHugues Fruchet 		 * go through exposure calculation
193419a81c14SSteve Longerbeam 		 */
193519a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
193619a81c14SSteve Longerbeam 	} else {
193719a81c14SSteve Longerbeam 		/*
193819a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
193919a81c14SSteve Longerbeam 		 * download firmware directly
194019a81c14SSteve Longerbeam 		 */
19413cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
194219a81c14SSteve Longerbeam 	}
194319a81c14SSteve Longerbeam 	if (ret < 0)
19443cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
19453cca8ef5SHugues Fruchet 
19463cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
19473cca8ef5SHugues Fruchet 	if (auto_gain)
19483cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
19493cca8ef5SHugues Fruchet 	if (auto_exp)
19503cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
195119a81c14SSteve Longerbeam 
1952ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
1953ce85705aSHugues Fruchet 	if (ret < 0)
1954ce85705aSHugues Fruchet 		return ret;
195519a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
195619a81c14SSteve Longerbeam 	if (ret < 0)
195719a81c14SSteve Longerbeam 		return ret;
195819a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
195919a81c14SSteve Longerbeam 	if (ret < 0)
196019a81c14SSteve Longerbeam 		return ret;
196119a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
196219a81c14SSteve Longerbeam 	if (ret < 0)
196319a81c14SSteve Longerbeam 		return ret;
196419a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
196519a81c14SSteve Longerbeam 	if (ret < 0)
196619a81c14SSteve Longerbeam 		return ret;
196719a81c14SSteve Longerbeam 
196819a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
1969985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
197019a81c14SSteve Longerbeam 
197119a81c14SSteve Longerbeam 	return 0;
19723cca8ef5SHugues Fruchet 
19733cca8ef5SHugues Fruchet restore_auto_exp_gain:
19743cca8ef5SHugues Fruchet 	if (auto_exp)
19753cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
19763cca8ef5SHugues Fruchet restore_auto_gain:
19773cca8ef5SHugues Fruchet 	if (auto_gain)
19783cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
19793cca8ef5SHugues Fruchet 
19803cca8ef5SHugues Fruchet 	return ret;
198119a81c14SSteve Longerbeam }
198219a81c14SSteve Longerbeam 
198319ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
198419ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
198519ad26f9SAkinobu Mita 
198619a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
198719a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
198819a81c14SSteve Longerbeam {
198919a81c14SSteve Longerbeam 	int ret;
199019a81c14SSteve Longerbeam 
199119a81c14SSteve Longerbeam 	/* first load the initial register values */
199219a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
199319a81c14SSteve Longerbeam 	if (ret < 0)
199419a81c14SSteve Longerbeam 		return ret;
1995985cdcb0SHugues Fruchet 	sensor->last_mode = &ov5640_mode_init_data;
199619a81c14SSteve Longerbeam 
19978f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
19987851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
19997851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
20008f57c2f8SMaxime Ripard 	if (ret)
20018f57c2f8SMaxime Ripard 		return ret;
20028f57c2f8SMaxime Ripard 
200319a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2004985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
200519ad26f9SAkinobu Mita 	if (ret < 0)
200619ad26f9SAkinobu Mita 		return ret;
200719ad26f9SAkinobu Mita 
200819ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
200919a81c14SSteve Longerbeam }
201019a81c14SSteve Longerbeam 
201119a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
201219a81c14SSteve Longerbeam {
20131fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
201419a81c14SSteve Longerbeam }
201519a81c14SSteve Longerbeam 
201619a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
201719a81c14SSteve Longerbeam {
201819a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
201919a81c14SSteve Longerbeam 		return;
202019a81c14SSteve Longerbeam 
20211fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
202219a81c14SSteve Longerbeam 
202319a81c14SSteve Longerbeam 	/* camera power cycle */
202419a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
202519a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
202619a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
202719a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
202819a81c14SSteve Longerbeam 
20291fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
203019a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
203119a81c14SSteve Longerbeam 
20321fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
20331d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
203419a81c14SSteve Longerbeam }
203519a81c14SSteve Longerbeam 
20360f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
203719a81c14SSteve Longerbeam {
20380f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
20390f7acb52SHugues Fruchet 	int ret;
204019a81c14SSteve Longerbeam 
20410f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
20420f7acb52SHugues Fruchet 	if (ret) {
20430f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
20440f7acb52SHugues Fruchet 			__func__);
20450f7acb52SHugues Fruchet 		return ret;
20460f7acb52SHugues Fruchet 	}
204719a81c14SSteve Longerbeam 
204819a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
204919a81c14SSteve Longerbeam 				    sensor->supplies);
20500f7acb52SHugues Fruchet 	if (ret) {
20510f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
20520f7acb52SHugues Fruchet 			__func__);
205319a81c14SSteve Longerbeam 		goto xclk_off;
20540f7acb52SHugues Fruchet 	}
205519a81c14SSteve Longerbeam 
205619a81c14SSteve Longerbeam 	ov5640_reset(sensor);
205719a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
205819a81c14SSteve Longerbeam 
205919a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
206019a81c14SSteve Longerbeam 	if (ret)
206119a81c14SSteve Longerbeam 		goto power_off;
206219a81c14SSteve Longerbeam 
20630f7acb52SHugues Fruchet 	return 0;
20640f7acb52SHugues Fruchet 
20650f7acb52SHugues Fruchet power_off:
20660f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
20670f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
20680f7acb52SHugues Fruchet xclk_off:
20690f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
20700f7acb52SHugues Fruchet 	return ret;
20710f7acb52SHugues Fruchet }
20720f7acb52SHugues Fruchet 
20730f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
20740f7acb52SHugues Fruchet {
20750f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
20760f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
20770f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
20780f7acb52SHugues Fruchet }
20790f7acb52SHugues Fruchet 
2080b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2081b1751ae6SLad Prabhakar {
2082b1751ae6SLad Prabhakar 	int ret;
2083b1751ae6SLad Prabhakar 
2084b1751ae6SLad Prabhakar 	if (!on) {
2085b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2086b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2087b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2088b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2089b1751ae6SLad Prabhakar 		return 0;
2090b1751ae6SLad Prabhakar 	}
2091b1751ae6SLad Prabhakar 
2092b1751ae6SLad Prabhakar 	/*
2093b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2094b1751ae6SLad Prabhakar 	 *
2095b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2096b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2097b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2098b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2099b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2100b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2101b1751ae6SLad Prabhakar 	 */
2102b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2103b1751ae6SLad Prabhakar 	if (ret)
2104b1751ae6SLad Prabhakar 		return ret;
2105b1751ae6SLad Prabhakar 
2106b1751ae6SLad Prabhakar 	/*
2107b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2108b1751ae6SLad Prabhakar 	 *
2109b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2110b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2111b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2112b1751ae6SLad Prabhakar 	 */
2113b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2114b1751ae6SLad Prabhakar 	if (ret)
2115b1751ae6SLad Prabhakar 		return ret;
2116b1751ae6SLad Prabhakar 
2117b1751ae6SLad Prabhakar 	/*
2118b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2119b1751ae6SLad Prabhakar 	 *
2120b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2121b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2122b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2123b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2124b1751ae6SLad Prabhakar 	 */
2125b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2126b1751ae6SLad Prabhakar 	if (ret)
2127b1751ae6SLad Prabhakar 		return ret;
2128b1751ae6SLad Prabhakar 
2129b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2130b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2131b1751ae6SLad Prabhakar 
2132b1751ae6SLad Prabhakar 	return 0;
2133b1751ae6SLad Prabhakar }
2134b1751ae6SLad Prabhakar 
2135576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2136576f5d4bSLad Prabhakar {
2137311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
213868579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
213968579b32SHugues Fruchet 	u8 polarities = 0;
2140576f5d4bSLad Prabhakar 	int ret;
2141576f5d4bSLad Prabhakar 
2142576f5d4bSLad Prabhakar 	if (!on) {
2143576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
214468579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2145311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2146311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2147576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2148576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2149576f5d4bSLad Prabhakar 		return 0;
2150576f5d4bSLad Prabhakar 	}
2151576f5d4bSLad Prabhakar 
2152576f5d4bSLad Prabhakar 	/*
2153311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2154311a6408SLad Prabhakar 	 *
2155311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2156311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2157311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2158311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2159311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2160311a6408SLad Prabhakar 	 *
2161311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2162311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2163311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2164311a6408SLad Prabhakar 	 * polarity will be as below:
2165311a6408SLad Prabhakar 	 * - VSYNC:	active high
2166311a6408SLad Prabhakar 	 * - HREF:	active low
2167311a6408SLad Prabhakar 	 * - PCLK:	active low
216868579b32SHugues Fruchet 	 *
216968579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2170311a6408SLad Prabhakar 	 */
217168579b32SHugues Fruchet 
217268579b32SHugues Fruchet 	/*
217368579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
217468579b32SHugues Fruchet 	 *
217568579b32SHugues Fruchet 	 * CCIR656 CTRL00
217668579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
217768579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
217868579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
217968579b32SHugues Fruchet 	 * - [5]:	Fixed f value
218068579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
218168579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
218268579b32SHugues Fruchet 	 * - [1]:	Clip data disable
218368579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
218468579b32SHugues Fruchet 	 *
218568579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
218668579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
218768579b32SHugues Fruchet 	 * - CCIR656 mode enable
218868579b32SHugues Fruchet 	 * - auto generation of sync codes
218968579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
219068579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
219168579b32SHugues Fruchet 	 */
219268579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
219368579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
219468579b32SHugues Fruchet 	if (ret)
219568579b32SHugues Fruchet 		return ret;
219668579b32SHugues Fruchet 
2197311a6408SLad Prabhakar 	/*
2198311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2199311a6408SLad Prabhakar 	 *
2200311a6408SLad Prabhakar 	 * POLARITY CTRL0
2201311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2202311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2203311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2204311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2205311a6408SLad Prabhakar 	 *		and 1 is active low...)
2206311a6408SLad Prabhakar 	 */
220768579b32SHugues Fruchet 	if (!bt656) {
2208311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
220968579b32SHugues Fruchet 			polarities |= BIT(1);
2210311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
221168579b32SHugues Fruchet 			polarities |= BIT(0);
221268579b32SHugues Fruchet 	}
221368579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
221468579b32SHugues Fruchet 		polarities |= BIT(5);
2215311a6408SLad Prabhakar 
221668579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2217311a6408SLad Prabhakar 	if (ret)
2218311a6408SLad Prabhakar 		return ret;
2219311a6408SLad Prabhakar 
2220311a6408SLad Prabhakar 	/*
222168579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2222311a6408SLad Prabhakar 	 *
2223311a6408SLad Prabhakar 	 * MIPI CONTROL 00
222468579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
222568579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
222668579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2227311a6408SLad Prabhakar 	 */
2228311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2229311a6408SLad Prabhakar 	if (ret)
2230311a6408SLad Prabhakar 		return ret;
2231311a6408SLad Prabhakar 
2232311a6408SLad Prabhakar 	/*
2233576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2234576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2235576f5d4bSLad Prabhakar 	 *
2236576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2237576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2238576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2239576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2240576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2241576f5d4bSLad Prabhakar 	 */
22424039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
224368579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2244576f5d4bSLad Prabhakar 	if (ret)
2245576f5d4bSLad Prabhakar 		return ret;
2246576f5d4bSLad Prabhakar 
2247576f5d4bSLad Prabhakar 	/*
2248576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2249576f5d4bSLad Prabhakar 	 *
2250576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2251576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2252576f5d4bSLad Prabhakar 	 */
2253576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2254576f5d4bSLad Prabhakar }
2255576f5d4bSLad Prabhakar 
22560f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
22570f7acb52SHugues Fruchet {
22580f7acb52SHugues Fruchet 	int ret = 0;
22590f7acb52SHugues Fruchet 
22600f7acb52SHugues Fruchet 	if (on) {
22610f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
22620f7acb52SHugues Fruchet 		if (ret)
22630f7acb52SHugues Fruchet 			return ret;
22640f7acb52SHugues Fruchet 
226519a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
226619a81c14SSteve Longerbeam 		if (ret)
226719a81c14SSteve Longerbeam 			goto power_off;
2268b1751ae6SLad Prabhakar 	}
226919a81c14SSteve Longerbeam 
2270576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2271b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2272576f5d4bSLad Prabhakar 	else
2273576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2274b1751ae6SLad Prabhakar 	if (ret)
2275b1751ae6SLad Prabhakar 		goto power_off;
2276aa4bb8b8SJacopo Mondi 
2277b1751ae6SLad Prabhakar 	if (!on)
2278aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
227919a81c14SSteve Longerbeam 
228019a81c14SSteve Longerbeam 	return 0;
228119a81c14SSteve Longerbeam 
228219a81c14SSteve Longerbeam power_off:
22830f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
228419a81c14SSteve Longerbeam 	return ret;
228519a81c14SSteve Longerbeam }
228619a81c14SSteve Longerbeam 
228719a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
228819a81c14SSteve Longerbeam 
228919a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
229019a81c14SSteve Longerbeam {
229119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
229219a81c14SSteve Longerbeam 	int ret = 0;
229319a81c14SSteve Longerbeam 
229419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
229519a81c14SSteve Longerbeam 
229619a81c14SSteve Longerbeam 	/*
229719a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
229819a81c14SSteve Longerbeam 	 * update the power state.
229919a81c14SSteve Longerbeam 	 */
230019a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
230119a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
230219a81c14SSteve Longerbeam 		if (ret)
230319a81c14SSteve Longerbeam 			goto out;
230419a81c14SSteve Longerbeam 	}
230519a81c14SSteve Longerbeam 
230619a81c14SSteve Longerbeam 	/* Update the power count. */
230719a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
230819a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
230919a81c14SSteve Longerbeam out:
231019a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
231119a81c14SSteve Longerbeam 
231219a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
231319a81c14SSteve Longerbeam 		/* restore controls */
231419a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
231519a81c14SSteve Longerbeam 	}
231619a81c14SSteve Longerbeam 
231719a81c14SSteve Longerbeam 	return ret;
231819a81c14SSteve Longerbeam }
231919a81c14SSteve Longerbeam 
232019a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
232119a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
232219a81c14SSteve Longerbeam 				     u32 width, u32 height)
232319a81c14SSteve Longerbeam {
232419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
23256530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2326f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2327f6cc192fSMaxime Ripard 	int i;
232819a81c14SSteve Longerbeam 
232919a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2330e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
233119a81c14SSteve Longerbeam 
233219a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
233319a81c14SSteve Longerbeam 		fi->denominator = maxfps;
233419a81c14SSteve Longerbeam 		fi->numerator = 1;
2335e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2336e823fb16SMaxime Ripard 		goto find_mode;
233719a81c14SSteve Longerbeam 	}
233819a81c14SSteve Longerbeam 
2339f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2340f6cc192fSMaxime Ripard 			minfps, maxfps);
2341f6cc192fSMaxime Ripard 
2342f6cc192fSMaxime Ripard 	best_fps = minfps;
2343f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2344f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2345f6cc192fSMaxime Ripard 
2346f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2347f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2348f6cc192fSMaxime Ripard 			rate = i;
2349f6cc192fSMaxime Ripard 		}
2350f6cc192fSMaxime Ripard 	}
235119a81c14SSteve Longerbeam 
235219a81c14SSteve Longerbeam 	fi->numerator = 1;
2353f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
235419a81c14SSteve Longerbeam 
2355e823fb16SMaxime Ripard find_mode:
23565a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
23575a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
235819a81c14SSteve Longerbeam }
235919a81c14SSteve Longerbeam 
236019a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
23610d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
236219a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
236319a81c14SSteve Longerbeam {
236419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
236519a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
236619a81c14SSteve Longerbeam 
236719a81c14SSteve Longerbeam 	if (format->pad != 0)
236819a81c14SSteve Longerbeam 		return -EINVAL;
236919a81c14SSteve Longerbeam 
237019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
237119a81c14SSteve Longerbeam 
237219a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
23730d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
237419a81c14SSteve Longerbeam 						 format->pad);
237519a81c14SSteve Longerbeam 	else
237619a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
237719a81c14SSteve Longerbeam 
237819a81c14SSteve Longerbeam 	format->format = *fmt;
237919a81c14SSteve Longerbeam 
238019a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
238119a81c14SSteve Longerbeam 
238219a81c14SSteve Longerbeam 	return 0;
238319a81c14SSteve Longerbeam }
238419a81c14SSteve Longerbeam 
238519a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
238619a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
238719a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
238819a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
238919a81c14SSteve Longerbeam {
239019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
239119a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2392e3ee691dSHugues Fruchet 	int i;
239319a81c14SSteve Longerbeam 
239419a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
239519a81c14SSteve Longerbeam 	if (!mode)
239619a81c14SSteve Longerbeam 		return -EINVAL;
2397dba13a0bSMaxime Ripard 	fmt->width = mode->hact;
2398dba13a0bSMaxime Ripard 	fmt->height = mode->vact;
239919a81c14SSteve Longerbeam 
240019a81c14SSteve Longerbeam 	if (new_mode)
240119a81c14SSteve Longerbeam 		*new_mode = mode;
2402e3ee691dSHugues Fruchet 
2403e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2404e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2405e3ee691dSHugues Fruchet 			break;
2406e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2407e6441fdeSHugues Fruchet 		i = 0;
2408e6441fdeSHugues Fruchet 
2409e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2410e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2411e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2412e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2413e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2414e3ee691dSHugues Fruchet 
241519a81c14SSteve Longerbeam 	return 0;
241619a81c14SSteve Longerbeam }
241719a81c14SSteve Longerbeam 
2418*3c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
2419*3c28588fSJacopo Mondi {
2420*3c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
2421*3c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
2422*3c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
2423*3c28588fSJacopo Mondi 	unsigned int i = 0;
2424*3c28588fSJacopo Mondi 	u32 pixel_rate;
2425*3c28588fSJacopo Mondi 	s64 link_freq;
2426*3c28588fSJacopo Mondi 	u32 num_lanes;
2427*3c28588fSJacopo Mondi 	u32 bpp;
2428*3c28588fSJacopo Mondi 
2429*3c28588fSJacopo Mondi 	/*
2430*3c28588fSJacopo Mondi 	 * Update the pixel rate control value.
2431*3c28588fSJacopo Mondi 	 *
2432*3c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
2433*3c28588fSJacopo Mondi 	 */
2434*3c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
2435*3c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
2436*3c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
2437*3c28588fSJacopo Mondi 
2438*3c28588fSJacopo Mondi 		return 0;
2439*3c28588fSJacopo Mondi 	}
2440*3c28588fSJacopo Mondi 
2441*3c28588fSJacopo Mondi 	/*
2442*3c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
2443*3c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
2444*3c28588fSJacopo Mondi 	 *
2445*3c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
2446*3c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
2447*3c28588fSJacopo Mondi 	 */
2448*3c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
2449*3c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
2450*3c28588fSJacopo Mondi 	do {
2451*3c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
2452*3c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
2453*3c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
2454*3c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
2455*3c28588fSJacopo Mondi 
2456*3c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
2457*3c28588fSJacopo Mondi 
2458*3c28588fSJacopo Mondi 	/*
2459*3c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
2460*3c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
2461*3c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
2462*3c28588fSJacopo Mondi 	 *
2463*3c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
2464*3c28588fSJacopo Mondi 	 * correctly to userspace.
2465*3c28588fSJacopo Mondi 	 */
2466*3c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
2467*3c28588fSJacopo Mondi 		pixel_rate /= 2;
2468*3c28588fSJacopo Mondi 		link_freq /= 2;
2469*3c28588fSJacopo Mondi 	}
2470*3c28588fSJacopo Mondi 
2471*3c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
2472*3c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
2473*3c28588fSJacopo Mondi 			break;
2474*3c28588fSJacopo Mondi 	}
2475*3c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
2476*3c28588fSJacopo Mondi 
2477*3c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
2478*3c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
2479*3c28588fSJacopo Mondi 
2480*3c28588fSJacopo Mondi 	return 0;
2481*3c28588fSJacopo Mondi }
2482*3c28588fSJacopo Mondi 
248319a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
24840d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
248519a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
248619a81c14SSteve Longerbeam {
248719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
248819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2489e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
249019a81c14SSteve Longerbeam 	int ret;
249119a81c14SSteve Longerbeam 
249219a81c14SSteve Longerbeam 	if (format->pad != 0)
249319a81c14SSteve Longerbeam 		return -EINVAL;
249419a81c14SSteve Longerbeam 
249519a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
249619a81c14SSteve Longerbeam 
249719a81c14SSteve Longerbeam 	if (sensor->streaming) {
249819a81c14SSteve Longerbeam 		ret = -EBUSY;
249919a81c14SSteve Longerbeam 		goto out;
250019a81c14SSteve Longerbeam 	}
250119a81c14SSteve Longerbeam 
2502e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
250319a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
250419a81c14SSteve Longerbeam 	if (ret)
250519a81c14SSteve Longerbeam 		goto out;
250619a81c14SSteve Longerbeam 
2507e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2508e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2509e738f5ddSMirela Rabulea 		goto out;
2510e738f5ddSMirela Rabulea 	}
251119a81c14SSteve Longerbeam 
25126949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
251319a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
251419a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
25156949d864SHugues Fruchet 	}
251607115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2517fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
251807115449SJacopo Mondi 
2519e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2520e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2521e738f5ddSMirela Rabulea 
2522*3c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
2523*3c28588fSJacopo Mondi 
252419a81c14SSteve Longerbeam out:
252519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
252619a81c14SSteve Longerbeam 	return ret;
252719a81c14SSteve Longerbeam }
252819a81c14SSteve Longerbeam 
2529e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2530e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2531e3ee691dSHugues Fruchet {
2532e3ee691dSHugues Fruchet 	int ret = 0;
2533d47c4126SHugues Fruchet 	bool is_jpeg = false;
2534b7ed3abdSLoic Poulain 	u8 fmt, mux;
2535e3ee691dSHugues Fruchet 
2536e3ee691dSHugues Fruchet 	switch (format->code) {
25371536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2538e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2539e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2540b7ed3abdSLoic Poulain 		fmt = 0x3f;
2541b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2542e3ee691dSHugues Fruchet 		break;
25431536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2544e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2545e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2546b7ed3abdSLoic Poulain 		fmt = 0x30;
2547b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2548e3ee691dSHugues Fruchet 		break;
2549e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2550e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2551b7ed3abdSLoic Poulain 		fmt = 0x6F;
2552b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2553e3ee691dSHugues Fruchet 		break;
2554e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2555e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2556b7ed3abdSLoic Poulain 		fmt = 0x61;
2557b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2558e3ee691dSHugues Fruchet 		break;
2559d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2560d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2561b7ed3abdSLoic Poulain 		fmt = 0x30;
2562b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2563d47c4126SHugues Fruchet 		is_jpeg = true;
2564d47c4126SHugues Fruchet 		break;
2565b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2566b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2567b7ed3abdSLoic Poulain 		fmt = 0x00;
2568b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2569b7ed3abdSLoic Poulain 		break;
2570b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2571b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2572b7ed3abdSLoic Poulain 		fmt = 0x01;
2573b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2574b7ed3abdSLoic Poulain 		break;
2575b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2576b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2577b7ed3abdSLoic Poulain 		fmt = 0x02;
2578b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2579b7ed3abdSLoic Poulain 		break;
2580b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2581b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2582b7ed3abdSLoic Poulain 		fmt = 0x03;
2583b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2584b7ed3abdSLoic Poulain 		break;
2585e3ee691dSHugues Fruchet 	default:
2586e3ee691dSHugues Fruchet 		return -EINVAL;
2587e3ee691dSHugues Fruchet 	}
2588e3ee691dSHugues Fruchet 
2589e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2590b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2591e3ee691dSHugues Fruchet 	if (ret)
2592e3ee691dSHugues Fruchet 		return ret;
2593e3ee691dSHugues Fruchet 
2594e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2595b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2596d47c4126SHugues Fruchet 	if (ret)
2597d47c4126SHugues Fruchet 		return ret;
2598d47c4126SHugues Fruchet 
2599d47c4126SHugues Fruchet 	/*
2600d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2601d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2602d47c4126SHugues Fruchet 	 */
2603d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2604d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2605d47c4126SHugues Fruchet 	if (ret)
2606d47c4126SHugues Fruchet 		return ret;
2607d47c4126SHugues Fruchet 
2608d47c4126SHugues Fruchet 	/*
2609d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2610d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2611d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2612d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2613d47c4126SHugues Fruchet 	 */
2614d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2615d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2616d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2617d47c4126SHugues Fruchet 	if (ret)
2618d47c4126SHugues Fruchet 		return ret;
2619d47c4126SHugues Fruchet 
2620d47c4126SHugues Fruchet 	/*
2621d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2622d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2623d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2624d47c4126SHugues Fruchet 	 */
2625d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2626d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2627d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2628e3ee691dSHugues Fruchet }
262919a81c14SSteve Longerbeam 
263019a81c14SSteve Longerbeam /*
263119a81c14SSteve Longerbeam  * Sensor Controls.
263219a81c14SSteve Longerbeam  */
263319a81c14SSteve Longerbeam 
263419a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
263519a81c14SSteve Longerbeam {
263619a81c14SSteve Longerbeam 	int ret;
263719a81c14SSteve Longerbeam 
263819a81c14SSteve Longerbeam 	if (value) {
263919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
264019a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
264119a81c14SSteve Longerbeam 		if (ret)
264219a81c14SSteve Longerbeam 			return ret;
264319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
264419a81c14SSteve Longerbeam 	} else {
264519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
264619a81c14SSteve Longerbeam 	}
264719a81c14SSteve Longerbeam 
264819a81c14SSteve Longerbeam 	return ret;
264919a81c14SSteve Longerbeam }
265019a81c14SSteve Longerbeam 
265119a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
265219a81c14SSteve Longerbeam {
265319a81c14SSteve Longerbeam 	int ret;
265419a81c14SSteve Longerbeam 
265519a81c14SSteve Longerbeam 	if (value) {
265619a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
265719a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
265819a81c14SSteve Longerbeam 		if (ret)
265919a81c14SSteve Longerbeam 			return ret;
266019a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
266119a81c14SSteve Longerbeam 				       value & 0xff);
266219a81c14SSteve Longerbeam 	} else {
266319a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
266419a81c14SSteve Longerbeam 	}
266519a81c14SSteve Longerbeam 
266619a81c14SSteve Longerbeam 	return ret;
266719a81c14SSteve Longerbeam }
266819a81c14SSteve Longerbeam 
266919a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
267019a81c14SSteve Longerbeam {
267119a81c14SSteve Longerbeam 	int ret;
267219a81c14SSteve Longerbeam 
267319a81c14SSteve Longerbeam 	if (value) {
267419a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
267519a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
267619a81c14SSteve Longerbeam 		if (ret)
267719a81c14SSteve Longerbeam 			return ret;
267819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
267919a81c14SSteve Longerbeam 				       value & 0xff);
268019a81c14SSteve Longerbeam 		if (ret)
268119a81c14SSteve Longerbeam 			return ret;
268219a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
268319a81c14SSteve Longerbeam 				       value & 0xff);
268419a81c14SSteve Longerbeam 	} else {
268519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
268619a81c14SSteve Longerbeam 	}
268719a81c14SSteve Longerbeam 
268819a81c14SSteve Longerbeam 	return ret;
268919a81c14SSteve Longerbeam }
269019a81c14SSteve Longerbeam 
269119a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
269219a81c14SSteve Longerbeam {
269319a81c14SSteve Longerbeam 	int ret;
269419a81c14SSteve Longerbeam 
269519a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
269619a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
269719a81c14SSteve Longerbeam 	if (ret)
269819a81c14SSteve Longerbeam 		return ret;
269919a81c14SSteve Longerbeam 
270019a81c14SSteve Longerbeam 	if (!awb) {
270119a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
270219a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
270319a81c14SSteve Longerbeam 
270419a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
270519a81c14SSteve Longerbeam 		if (ret)
270619a81c14SSteve Longerbeam 			return ret;
270719a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
270819a81c14SSteve Longerbeam 	}
270919a81c14SSteve Longerbeam 
271019a81c14SSteve Longerbeam 	return ret;
271119a81c14SSteve Longerbeam }
271219a81c14SSteve Longerbeam 
27133cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
27143cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
271519a81c14SSteve Longerbeam {
271619a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
27173cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
271819a81c14SSteve Longerbeam 	int ret = 0;
271919a81c14SSteve Longerbeam 
272019a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
27213cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
272219a81c14SSteve Longerbeam 		if (ret)
272319a81c14SSteve Longerbeam 			return ret;
272419a81c14SSteve Longerbeam 	}
272519a81c14SSteve Longerbeam 
27263cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
272719a81c14SSteve Longerbeam 		u16 max_exp;
272819a81c14SSteve Longerbeam 
272919a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
273019a81c14SSteve Longerbeam 					&max_exp);
273119a81c14SSteve Longerbeam 		if (ret)
273219a81c14SSteve Longerbeam 			return ret;
273319a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
273419a81c14SSteve Longerbeam 		if (ret < 0)
273519a81c14SSteve Longerbeam 			return ret;
273619a81c14SSteve Longerbeam 		max_exp += ret;
27376146fde3SHugues Fruchet 		ret = 0;
273819a81c14SSteve Longerbeam 
273919a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
274019a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
274119a81c14SSteve Longerbeam 	}
274219a81c14SSteve Longerbeam 
274319a81c14SSteve Longerbeam 	return ret;
274419a81c14SSteve Longerbeam }
274519a81c14SSteve Longerbeam 
27463cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
274719a81c14SSteve Longerbeam {
274819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
274919a81c14SSteve Longerbeam 	int ret = 0;
275019a81c14SSteve Longerbeam 
275119a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
27523cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
275319a81c14SSteve Longerbeam 		if (ret)
275419a81c14SSteve Longerbeam 			return ret;
275519a81c14SSteve Longerbeam 	}
275619a81c14SSteve Longerbeam 
27573cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
27583cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
275919a81c14SSteve Longerbeam 
276019a81c14SSteve Longerbeam 	return ret;
276119a81c14SSteve Longerbeam }
276219a81c14SSteve Longerbeam 
27639f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
27649f6d7bacSChen-Yu Tsai 	"Disabled",
27659f6d7bacSChen-Yu Tsai 	"Color bars",
2766bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
2767bddc5cdfSChen-Yu Tsai 	"Color squares",
2768bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
27699f6d7bacSChen-Yu Tsai };
27709f6d7bacSChen-Yu Tsai 
2771a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
2772a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
2773a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
2774a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
2775a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
2776a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
2777a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
2778a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
2779a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
2780a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
2781a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
2782a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
2783a0c29afbSChen-Yu Tsai 
2784a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
2785a0c29afbSChen-Yu Tsai 	0,
27862aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
2787a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
2788bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
2789bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
2790bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
2791bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
2792a0c29afbSChen-Yu Tsai };
2793a0c29afbSChen-Yu Tsai 
279419a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
279519a81c14SSteve Longerbeam {
2796a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
2797a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
279819a81c14SSteve Longerbeam }
279919a81c14SSteve Longerbeam 
28001068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
28011068fecaSMylène Josserand {
28021068fecaSMylène Josserand 	int ret;
28031068fecaSMylène Josserand 
28041068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
28051068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
28061068fecaSMylène Josserand 			     0 : BIT(7));
28071068fecaSMylène Josserand 	if (ret)
28081068fecaSMylène Josserand 		return ret;
28091068fecaSMylène Josserand 
28101068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
28111068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
28121068fecaSMylène Josserand 			      BIT(2) : 0);
28131068fecaSMylène Josserand }
28141068fecaSMylène Josserand 
2815ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
2816ce85705aSHugues Fruchet {
2817ce85705aSHugues Fruchet 	/*
2818c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
2819c3f3ba3eSHugues Fruchet 	 *
2820ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
2821ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
2822ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
2823ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
2824ce85705aSHugues Fruchet 	 */
2825ce85705aSHugues Fruchet 
2826ce85705aSHugues Fruchet 	/*
2827ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2828ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
2829ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
2830ce85705aSHugues Fruchet 	 */
2831ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2832ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
2833c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
2834c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
2835ce85705aSHugues Fruchet }
2836ce85705aSHugues Fruchet 
2837ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
2838ce85705aSHugues Fruchet {
2839c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
2840c3f3ba3eSHugues Fruchet 
2841ce85705aSHugues Fruchet 	/*
2842ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2843ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
2844ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
2845ce85705aSHugues Fruchet 	 */
2846ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2847ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
2848c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
2849c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
2850ce85705aSHugues Fruchet }
2851ce85705aSHugues Fruchet 
285219a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
285319a81c14SSteve Longerbeam {
285419a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
285519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
285619a81c14SSteve Longerbeam 	int val;
285719a81c14SSteve Longerbeam 
285819a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
285919a81c14SSteve Longerbeam 
286019a81c14SSteve Longerbeam 	switch (ctrl->id) {
286119a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
286219a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
286319a81c14SSteve Longerbeam 		if (val < 0)
286419a81c14SSteve Longerbeam 			return val;
286519a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
286619a81c14SSteve Longerbeam 		break;
286719a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
286819a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
286919a81c14SSteve Longerbeam 		if (val < 0)
287019a81c14SSteve Longerbeam 			return val;
287119a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
287219a81c14SSteve Longerbeam 		break;
287319a81c14SSteve Longerbeam 	}
287419a81c14SSteve Longerbeam 
287519a81c14SSteve Longerbeam 	return 0;
287619a81c14SSteve Longerbeam }
287719a81c14SSteve Longerbeam 
287819a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
287919a81c14SSteve Longerbeam {
288019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
288119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
288219a81c14SSteve Longerbeam 	int ret;
288319a81c14SSteve Longerbeam 
288419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
288519a81c14SSteve Longerbeam 
288619a81c14SSteve Longerbeam 	/*
288719a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
288819a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
288919a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
289019a81c14SSteve Longerbeam 	 */
289119a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
289219a81c14SSteve Longerbeam 		return 0;
289319a81c14SSteve Longerbeam 
289419a81c14SSteve Longerbeam 	switch (ctrl->id) {
289519a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
289619a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
289719a81c14SSteve Longerbeam 		break;
289819a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
289919a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
290019a81c14SSteve Longerbeam 		break;
290119a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
290219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
290319a81c14SSteve Longerbeam 		break;
290419a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
290519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
290619a81c14SSteve Longerbeam 		break;
290719a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
290819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
290919a81c14SSteve Longerbeam 		break;
291019a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
291119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
291219a81c14SSteve Longerbeam 		break;
291319a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
291419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
291519a81c14SSteve Longerbeam 		break;
29161068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
29171068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
29181068fecaSMylène Josserand 		break;
2919ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
2920ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
2921ce85705aSHugues Fruchet 		break;
2922ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
2923ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
2924ce85705aSHugues Fruchet 		break;
292519a81c14SSteve Longerbeam 	default:
292619a81c14SSteve Longerbeam 		ret = -EINVAL;
292719a81c14SSteve Longerbeam 		break;
292819a81c14SSteve Longerbeam 	}
292919a81c14SSteve Longerbeam 
293019a81c14SSteve Longerbeam 	return ret;
293119a81c14SSteve Longerbeam }
293219a81c14SSteve Longerbeam 
293319a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
293419a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
293519a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
293619a81c14SSteve Longerbeam };
293719a81c14SSteve Longerbeam 
293819a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
293919a81c14SSteve Longerbeam {
294022845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
294119a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
294219a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
294319a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
294419a81c14SSteve Longerbeam 	int ret;
294519a81c14SSteve Longerbeam 
294619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
294719a81c14SSteve Longerbeam 
294819a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
294919a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
295019a81c14SSteve Longerbeam 
2951cc196e48SBenoit Parrot 	/* Clock related controls */
2952cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
295322845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
295422845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
295522845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
2956cc196e48SBenoit Parrot 
29577a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
29587a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
29597a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
29607a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
29617a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
29627a3b8d4bSJacopo Mondi 
296319a81c14SSteve Longerbeam 	/* Auto/manual white balance */
296419a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
296519a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
296619a81c14SSteve Longerbeam 					   0, 1, 1, 1);
296719a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
296819a81c14SSteve Longerbeam 						0, 4095, 1, 0);
296919a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
297019a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
297119a81c14SSteve Longerbeam 	/* Auto/manual exposure */
297219a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
297319a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
297419a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
297519a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
297619a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
297719a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
297819a81c14SSteve Longerbeam 	/* Auto/manual gain */
297919a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
298019a81c14SSteve Longerbeam 					     0, 1, 1, 1);
298119a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
298219a81c14SSteve Longerbeam 					0, 1023, 1, 0);
298319a81c14SSteve Longerbeam 
298419a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
298519a81c14SSteve Longerbeam 					      0, 255, 1, 64);
298619a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
298719a81c14SSteve Longerbeam 				       0, 359, 1, 0);
298819a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
298919a81c14SSteve Longerbeam 					    0, 255, 1, 0);
299019a81c14SSteve Longerbeam 	ctrls->test_pattern =
299119a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
299219a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
299319a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
2994ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
2995ce85705aSHugues Fruchet 					 0, 1, 1, 0);
2996ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
2997ce85705aSHugues Fruchet 					 0, 1, 1, 0);
299819a81c14SSteve Longerbeam 
29991068fecaSMylène Josserand 	ctrls->light_freq =
30001068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
30011068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
30021068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
30031068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
30041068fecaSMylène Josserand 
300519a81c14SSteve Longerbeam 	if (hdl->error) {
300619a81c14SSteve Longerbeam 		ret = hdl->error;
300719a81c14SSteve Longerbeam 		goto free_ctrls;
300819a81c14SSteve Longerbeam 	}
300919a81c14SSteve Longerbeam 
3010cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
30117a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
301219a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
301319a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
301419a81c14SSteve Longerbeam 
301519a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
301619a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
301719a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
301819a81c14SSteve Longerbeam 
301919a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
302019a81c14SSteve Longerbeam 	return 0;
302119a81c14SSteve Longerbeam 
302219a81c14SSteve Longerbeam free_ctrls:
302319a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
302419a81c14SSteve Longerbeam 	return ret;
302519a81c14SSteve Longerbeam }
302619a81c14SSteve Longerbeam 
302719a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
30280d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
302919a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
303019a81c14SSteve Longerbeam {
303119a81c14SSteve Longerbeam 	if (fse->pad != 0)
303219a81c14SSteve Longerbeam 		return -EINVAL;
303319a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
303419a81c14SSteve Longerbeam 		return -EINVAL;
303519a81c14SSteve Longerbeam 
303641d8d7f5SHugues Fruchet 	fse->min_width =
3037086c25f8SMaxime Ripard 		ov5640_mode_data[fse->index].hact;
303841d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
303941d8d7f5SHugues Fruchet 	fse->min_height =
3040086c25f8SMaxime Ripard 		ov5640_mode_data[fse->index].vact;
304141d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
304219a81c14SSteve Longerbeam 
304319a81c14SSteve Longerbeam 	return 0;
304419a81c14SSteve Longerbeam }
304519a81c14SSteve Longerbeam 
304619a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
304719a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
30480d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
304919a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
305019a81c14SSteve Longerbeam {
305119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
305219a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
305319a81c14SSteve Longerbeam 	int ret;
305419a81c14SSteve Longerbeam 
305519a81c14SSteve Longerbeam 	if (fie->pad != 0)
305619a81c14SSteve Longerbeam 		return -EINVAL;
305719a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
305819a81c14SSteve Longerbeam 		return -EINVAL;
305919a81c14SSteve Longerbeam 
306019a81c14SSteve Longerbeam 	tpf.numerator = 1;
306119a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
306219a81c14SSteve Longerbeam 
306319a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
306419a81c14SSteve Longerbeam 					fie->width, fie->height);
306519a81c14SSteve Longerbeam 	if (ret < 0)
306619a81c14SSteve Longerbeam 		return -EINVAL;
306719a81c14SSteve Longerbeam 
306819a81c14SSteve Longerbeam 	fie->interval = tpf;
306919a81c14SSteve Longerbeam 	return 0;
307019a81c14SSteve Longerbeam }
307119a81c14SSteve Longerbeam 
307219a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
307319a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
307419a81c14SSteve Longerbeam {
307519a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
307619a81c14SSteve Longerbeam 
307719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
307819a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
307919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
308019a81c14SSteve Longerbeam 
308119a81c14SSteve Longerbeam 	return 0;
308219a81c14SSteve Longerbeam }
308319a81c14SSteve Longerbeam 
308419a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
308519a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
308619a81c14SSteve Longerbeam {
308719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
308819a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
308919a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
309019a81c14SSteve Longerbeam 
309119a81c14SSteve Longerbeam 	if (fi->pad != 0)
309219a81c14SSteve Longerbeam 		return -EINVAL;
309319a81c14SSteve Longerbeam 
309419a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
309519a81c14SSteve Longerbeam 
309619a81c14SSteve Longerbeam 	if (sensor->streaming) {
309719a81c14SSteve Longerbeam 		ret = -EBUSY;
309819a81c14SSteve Longerbeam 		goto out;
309919a81c14SSteve Longerbeam 	}
310019a81c14SSteve Longerbeam 
310119a81c14SSteve Longerbeam 	mode = sensor->current_mode;
310219a81c14SSteve Longerbeam 
310319a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
3104dba13a0bSMaxime Ripard 					       mode->hact, mode->vact);
3105e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3106e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3107e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3108e823fb16SMaxime Ripard 		goto out;
3109e823fb16SMaxime Ripard 	}
311019a81c14SSteve Longerbeam 
31113c4a7372SHugues Fruchet 	mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
3112dba13a0bSMaxime Ripard 				mode->vact, true);
31133c4a7372SHugues Fruchet 	if (!mode) {
31143c4a7372SHugues Fruchet 		ret = -EINVAL;
31153c4a7372SHugues Fruchet 		goto out;
31163c4a7372SHugues Fruchet 	}
31173c4a7372SHugues Fruchet 
31180929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
31190929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
31200929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
31210929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
31223c4a7372SHugues Fruchet 		sensor->current_mode = mode;
312319a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3124cc196e48SBenoit Parrot 
3125cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3126cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
31276949d864SHugues Fruchet 	}
312819a81c14SSteve Longerbeam out:
312919a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
313019a81c14SSteve Longerbeam 	return ret;
313119a81c14SSteve Longerbeam }
313219a81c14SSteve Longerbeam 
313319a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
31340d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
313519a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
313619a81c14SSteve Longerbeam {
313719a81c14SSteve Longerbeam 	if (code->pad != 0)
313819a81c14SSteve Longerbeam 		return -EINVAL;
3139e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
314019a81c14SSteve Longerbeam 		return -EINVAL;
314119a81c14SSteve Longerbeam 
3142e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
314319a81c14SSteve Longerbeam 	return 0;
314419a81c14SSteve Longerbeam }
314519a81c14SSteve Longerbeam 
314619a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
314719a81c14SSteve Longerbeam {
314819a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
314919a81c14SSteve Longerbeam 	int ret = 0;
315019a81c14SSteve Longerbeam 
315119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
315219a81c14SSteve Longerbeam 
315319a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
315419a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3155985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
315619a81c14SSteve Longerbeam 			if (ret)
315719a81c14SSteve Longerbeam 				goto out;
3158fb98e29fSHugues Fruchet 		}
3159e3ee691dSHugues Fruchet 
3160fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3161e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3162e3ee691dSHugues Fruchet 			if (ret)
3163e3ee691dSHugues Fruchet 				goto out;
3164fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
316519a81c14SSteve Longerbeam 		}
316619a81c14SSteve Longerbeam 
31678e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3168f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3169f22996dbSHugues Fruchet 		else
3170f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3171f22996dbSHugues Fruchet 
317219a81c14SSteve Longerbeam 		if (!ret)
317319a81c14SSteve Longerbeam 			sensor->streaming = enable;
317419a81c14SSteve Longerbeam 	}
317519a81c14SSteve Longerbeam out:
317619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
317719a81c14SSteve Longerbeam 	return ret;
317819a81c14SSteve Longerbeam }
317919a81c14SSteve Longerbeam 
318019a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
318119a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
31822d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
31832d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
31842d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
318519a81c14SSteve Longerbeam };
318619a81c14SSteve Longerbeam 
318719a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
318819a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
318919a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
319019a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
319119a81c14SSteve Longerbeam };
319219a81c14SSteve Longerbeam 
319319a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
319419a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
319519a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
319619a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
319719a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
319819a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
319919a81c14SSteve Longerbeam };
320019a81c14SSteve Longerbeam 
320119a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
320219a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
320319a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
320419a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
320519a81c14SSteve Longerbeam };
320619a81c14SSteve Longerbeam 
320719a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
320819a81c14SSteve Longerbeam {
320919a81c14SSteve Longerbeam 	int i;
321019a81c14SSteve Longerbeam 
321119a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
321219a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
321319a81c14SSteve Longerbeam 
321419a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
321519a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
321619a81c14SSteve Longerbeam 				       sensor->supplies);
321719a81c14SSteve Longerbeam }
321819a81c14SSteve Longerbeam 
32190f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
32200f7acb52SHugues Fruchet {
32210f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
32220f7acb52SHugues Fruchet 	int ret = 0;
32230f7acb52SHugues Fruchet 	u16 chip_id;
32240f7acb52SHugues Fruchet 
32250f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
32260f7acb52SHugues Fruchet 	if (ret)
32270f7acb52SHugues Fruchet 		return ret;
32280f7acb52SHugues Fruchet 
32290f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
32300f7acb52SHugues Fruchet 	if (ret) {
32310f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
32320f7acb52SHugues Fruchet 			__func__);
32330f7acb52SHugues Fruchet 		goto power_off;
32340f7acb52SHugues Fruchet 	}
32350f7acb52SHugues Fruchet 
32360f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
32370f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
32380f7acb52SHugues Fruchet 			__func__, chip_id);
32390f7acb52SHugues Fruchet 		ret = -ENXIO;
32400f7acb52SHugues Fruchet 	}
32410f7acb52SHugues Fruchet 
32420f7acb52SHugues Fruchet power_off:
32430f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
32440f7acb52SHugues Fruchet 	return ret;
32450f7acb52SHugues Fruchet }
32460f7acb52SHugues Fruchet 
3247e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
324819a81c14SSteve Longerbeam {
324919a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
325019a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
325119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3252e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3253c3f3ba3eSHugues Fruchet 	u32 rotation;
325419a81c14SSteve Longerbeam 	int ret;
325519a81c14SSteve Longerbeam 
325619a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
325719a81c14SSteve Longerbeam 	if (!sensor)
325819a81c14SSteve Longerbeam 		return -ENOMEM;
325919a81c14SSteve Longerbeam 
326019a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3261fb98e29fSHugues Fruchet 
3262fb98e29fSHugues Fruchet 	/*
3263fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3264fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3265fb98e29fSHugues Fruchet 	 */
3266e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3267fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3268fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3269e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3270e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3271e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3272e6441fdeSHugues Fruchet 	fmt->width = 640;
3273e6441fdeSHugues Fruchet 	fmt->height = 480;
3274e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
327519a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
327619a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
327719a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
327819a81c14SSteve Longerbeam 	sensor->current_mode =
3279086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3280985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
3281*3c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
328219a81c14SSteve Longerbeam 
328319a81c14SSteve Longerbeam 	sensor->ae_target = 52;
328419a81c14SSteve Longerbeam 
3285c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3286c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3287c3f3ba3eSHugues Fruchet 				       &rotation);
3288c3f3ba3eSHugues Fruchet 	if (!ret) {
3289c3f3ba3eSHugues Fruchet 		switch (rotation) {
3290c3f3ba3eSHugues Fruchet 		case 180:
3291c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
32921771e9fbSGustavo A. R. Silva 			fallthrough;
3293c3f3ba3eSHugues Fruchet 		case 0:
3294c3f3ba3eSHugues Fruchet 			break;
3295c3f3ba3eSHugues Fruchet 		default:
3296c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3297c3f3ba3eSHugues Fruchet 				 rotation);
3298c3f3ba3eSHugues Fruchet 		}
3299c3f3ba3eSHugues Fruchet 	}
3300c3f3ba3eSHugues Fruchet 
3301ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3302ce96bcf5SSakari Ailus 						  NULL);
330319a81c14SSteve Longerbeam 	if (!endpoint) {
330419a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
330519a81c14SSteve Longerbeam 		return -EINVAL;
330619a81c14SSteve Longerbeam 	}
330719a81c14SSteve Longerbeam 
330819a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
330919a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
331019a81c14SSteve Longerbeam 	if (ret) {
331119a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
331219a81c14SSteve Longerbeam 		return ret;
331319a81c14SSteve Longerbeam 	}
331419a81c14SSteve Longerbeam 
33152c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
33162c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
33172c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
33182c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
33192c61e48dSLad Prabhakar 		return -EINVAL;
33202c61e48dSLad Prabhakar 	}
33212c61e48dSLad Prabhakar 
332219a81c14SSteve Longerbeam 	/* get system clock (xclk) */
332319a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
332419a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
332519a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
332619a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
332719a81c14SSteve Longerbeam 	}
332819a81c14SSteve Longerbeam 
332919a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
333019a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
333119a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
333219a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
333319a81c14SSteve Longerbeam 			sensor->xclk_freq);
333419a81c14SSteve Longerbeam 		return -EINVAL;
333519a81c14SSteve Longerbeam 	}
333619a81c14SSteve Longerbeam 
333719a81c14SSteve Longerbeam 	/* request optional power down pin */
333819a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
333919a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
33408791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
33418791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
33428791a102SFabio Estevam 
334319a81c14SSteve Longerbeam 	/* request optional reset pin */
334419a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
334519a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
33468791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
33478791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
334819a81c14SSteve Longerbeam 
334919a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
335019a81c14SSteve Longerbeam 
33512d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
33522d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
335319a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
335419a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
335519a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
335619a81c14SSteve Longerbeam 	if (ret)
335719a81c14SSteve Longerbeam 		return ret;
335819a81c14SSteve Longerbeam 
335919a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
336019a81c14SSteve Longerbeam 	if (ret)
336119a81c14SSteve Longerbeam 		return ret;
336219a81c14SSteve Longerbeam 
336319a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
336419a81c14SSteve Longerbeam 
33650f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
33660f7acb52SHugues Fruchet 	if (ret)
33670f7acb52SHugues Fruchet 		goto entity_cleanup;
33680f7acb52SHugues Fruchet 
336919a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
337019a81c14SSteve Longerbeam 	if (ret)
337119a81c14SSteve Longerbeam 		goto entity_cleanup;
337219a81c14SSteve Longerbeam 
337315786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
337419a81c14SSteve Longerbeam 	if (ret)
337519a81c14SSteve Longerbeam 		goto free_ctrls;
337619a81c14SSteve Longerbeam 
337719a81c14SSteve Longerbeam 	return 0;
337819a81c14SSteve Longerbeam 
337919a81c14SSteve Longerbeam free_ctrls:
338019a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
338119a81c14SSteve Longerbeam entity_cleanup:
338219a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3383bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
338419a81c14SSteve Longerbeam 	return ret;
338519a81c14SSteve Longerbeam }
338619a81c14SSteve Longerbeam 
338719a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
338819a81c14SSteve Longerbeam {
338919a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
339019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
339119a81c14SSteve Longerbeam 
339219a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
339319a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
339419a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3395bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
339619a81c14SSteve Longerbeam 
339719a81c14SSteve Longerbeam 	return 0;
339819a81c14SSteve Longerbeam }
339919a81c14SSteve Longerbeam 
340019a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
340119a81c14SSteve Longerbeam 	{"ov5640", 0},
340219a81c14SSteve Longerbeam 	{},
340319a81c14SSteve Longerbeam };
340419a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
340519a81c14SSteve Longerbeam 
340619a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
340719a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
340819a81c14SSteve Longerbeam 	{ /* sentinel */ }
340919a81c14SSteve Longerbeam };
341019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
341119a81c14SSteve Longerbeam 
341219a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
341319a81c14SSteve Longerbeam 	.driver = {
341419a81c14SSteve Longerbeam 		.name  = "ov5640",
341519a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
341619a81c14SSteve Longerbeam 	},
341719a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3418e6714993SKieran Bingham 	.probe_new = ov5640_probe,
341919a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
342019a81c14SSteve Longerbeam };
342119a81c14SSteve Longerbeam 
342219a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
342319a81c14SSteve Longerbeam 
342419a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
342519a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3426