xref: /openbmc/linux/drivers/media/i2c/ov5640.c (revision 6c957ed7)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
219a81c14SSteve Longerbeam /*
319a81c14SSteve Longerbeam  * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. All Rights Reserved.
419a81c14SSteve Longerbeam  * Copyright (C) 2014-2017 Mentor Graphics Inc.
519a81c14SSteve Longerbeam  */
619a81c14SSteve Longerbeam 
719a81c14SSteve Longerbeam #include <linux/clk.h>
819a81c14SSteve Longerbeam #include <linux/clk-provider.h>
919a81c14SSteve Longerbeam #include <linux/clkdev.h>
1019a81c14SSteve Longerbeam #include <linux/ctype.h>
1119a81c14SSteve Longerbeam #include <linux/delay.h>
1219a81c14SSteve Longerbeam #include <linux/device.h>
1341d8d7f5SHugues Fruchet #include <linux/gpio/consumer.h>
1419a81c14SSteve Longerbeam #include <linux/i2c.h>
1519a81c14SSteve Longerbeam #include <linux/init.h>
1619a81c14SSteve Longerbeam #include <linux/module.h>
1719a81c14SSteve Longerbeam #include <linux/of_device.h>
1841d8d7f5SHugues Fruchet #include <linux/regulator/consumer.h>
1919a81c14SSteve Longerbeam #include <linux/slab.h>
2019a81c14SSteve Longerbeam #include <linux/types.h>
2119a81c14SSteve Longerbeam #include <media/v4l2-async.h>
2219a81c14SSteve Longerbeam #include <media/v4l2-ctrls.h>
2319a81c14SSteve Longerbeam #include <media/v4l2-device.h>
242d18fbc5SAkinobu Mita #include <media/v4l2-event.h>
2519a81c14SSteve Longerbeam #include <media/v4l2-fwnode.h>
2619a81c14SSteve Longerbeam #include <media/v4l2-subdev.h>
2719a81c14SSteve Longerbeam 
2819a81c14SSteve Longerbeam /* min/typical/max system clock (xclk) frequencies */
2919a81c14SSteve Longerbeam #define OV5640_XCLK_MIN  6000000
3041cb1c73SPhilipp Puschmann #define OV5640_XCLK_MAX 54000000
3119a81c14SSteve Longerbeam 
3219a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c
3319a81c14SSteve Longerbeam 
343c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX		490000000U
353c28588fSJacopo Mondi 
36d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02		0x3002
37d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02	0x3006
38f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0		0x3008
393b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN	0x42
403b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP	0x02
4119a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID		0x300a
42f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00	0x300e
43f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01	0x3017
44f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02	0x3018
4519a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00		0x3019
46f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1	0x302e
4719a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0		0x3034
4819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1		0x3035
4919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2		0x3036
5019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3		0x3037
5119a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID		0x3100
52f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1	0x3103
5319a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER	0x3108
5419a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN		0x3400
5519a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN		0x3402
5619a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN		0x3404
5719a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL	0x3406
5819a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI	0x3500
5919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED	0x3501
6019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO	0x3502
6119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL	0x3503
6219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN	0x350a
6319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS		0x350c
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
93*6c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD		0x4837
94e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL	0x501f
9519a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1	0x503d
9619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0		0x5580
9719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1		0x5581
9819a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3		0x5583
9919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4		0x5584
10019a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5		0x5585
10119a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT		0x56a1
10219a81c14SSteve Longerbeam 
10319a81c14SSteve Longerbeam enum ov5640_mode_id {
10432ea5e05SHugues Fruchet 	OV5640_MODE_QQVGA_160_120 = 0,
10532ea5e05SHugues Fruchet 	OV5640_MODE_QCIF_176_144,
10619a81c14SSteve Longerbeam 	OV5640_MODE_QVGA_320_240,
10719a81c14SSteve Longerbeam 	OV5640_MODE_VGA_640_480,
10819a81c14SSteve Longerbeam 	OV5640_MODE_NTSC_720_480,
10919a81c14SSteve Longerbeam 	OV5640_MODE_PAL_720_576,
11019a81c14SSteve Longerbeam 	OV5640_MODE_XGA_1024_768,
11119a81c14SSteve Longerbeam 	OV5640_MODE_720P_1280_720,
11219a81c14SSteve Longerbeam 	OV5640_MODE_1080P_1920_1080,
11319a81c14SSteve Longerbeam 	OV5640_MODE_QSXGA_2592_1944,
11419a81c14SSteve Longerbeam 	OV5640_NUM_MODES,
11519a81c14SSteve Longerbeam };
11619a81c14SSteve Longerbeam 
11719a81c14SSteve Longerbeam enum ov5640_frame_rate {
11819a81c14SSteve Longerbeam 	OV5640_15_FPS = 0,
11919a81c14SSteve Longerbeam 	OV5640_30_FPS,
120e823fb16SMaxime Ripard 	OV5640_60_FPS,
12119a81c14SSteve Longerbeam 	OV5640_NUM_FRAMERATES,
12219a81c14SSteve Longerbeam };
12319a81c14SSteve Longerbeam 
12422845bf2SJacopo Mondi enum ov5640_pixel_rate_id {
12522845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_168M,
12622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_148M,
12722845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_124M,
12822845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
12922845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_48M,
13022845bf2SJacopo Mondi 	OV5640_NUM_PIXEL_RATES,
13122845bf2SJacopo Mondi };
13222845bf2SJacopo Mondi 
13322845bf2SJacopo Mondi /*
13422845bf2SJacopo Mondi  * The chip manual suggests 24/48/96/192 MHz pixel clocks.
13522845bf2SJacopo Mondi  *
13622845bf2SJacopo Mondi  * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
13722845bf2SJacopo Mondi  * full resolution mode @15 FPS.
13822845bf2SJacopo Mondi  */
13922845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = {
14022845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_168M] = 168000000,
14122845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_148M] = 148000000,
14222845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_124M] = 124000000,
14322845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_96M] = 96000000,
14422845bf2SJacopo Mondi 	[OV5640_PIXEL_RATE_48M] = 48000000,
14522845bf2SJacopo Mondi };
14622845bf2SJacopo Mondi 
1477a3b8d4bSJacopo Mondi /*
1487a3b8d4bSJacopo Mondi  * MIPI CSI-2 link frequencies.
1497a3b8d4bSJacopo Mondi  *
1507a3b8d4bSJacopo Mondi  * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
1517a3b8d4bSJacopo Mondi  * data_lanes = (1, 2)
1527a3b8d4bSJacopo Mondi  *
1537a3b8d4bSJacopo Mondi  * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
1547a3b8d4bSJacopo Mondi  */
1557a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = {
1567a3b8d4bSJacopo Mondi 	992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
1577a3b8d4bSJacopo Mondi 	592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
1587a3b8d4bSJacopo Mondi 	384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
1597a3b8d4bSJacopo Mondi 	248000000, 192000000, 192000000, 192000000, 96000000,
1607a3b8d4bSJacopo Mondi };
1617a3b8d4bSJacopo Mondi 
1627a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
1637a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ	13
1647a3b8d4bSJacopo Mondi 
165b7ed3abdSLoic Poulain enum ov5640_format_mux {
166b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_YUV422 = 0,
167b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RGB,
168b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_DITHER,
169b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_DPC,
170b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_SNR_RAW,
171b7ed3abdSLoic Poulain 	OV5640_FMT_MUX_RAW_CIP,
172b7ed3abdSLoic Poulain };
173b7ed3abdSLoic Poulain 
1742d7671f6SJacopo Mondi static const struct ov5640_pixfmt {
175e3ee691dSHugues Fruchet 	u32 code;
176e3ee691dSHugues Fruchet 	u32 colorspace;
1772d7671f6SJacopo Mondi 	u8 bpp;
1782d7671f6SJacopo Mondi } ov5640_formats[] = {
1792d7671f6SJacopo Mondi 	{
1802d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_JPEG_1X8,
1812d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_JPEG,
1822d7671f6SJacopo Mondi 		.bpp = 16,
1832d7671f6SJacopo Mondi 	}, {
1842d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_2X8,
1852d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1862d7671f6SJacopo Mondi 		.bpp = 16,
1872d7671f6SJacopo Mondi 	}, {
1882d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_UYVY8_1X16,
1892d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1902d7671f6SJacopo Mondi 		.bpp = 16,
1912d7671f6SJacopo Mondi 	}, {
1922d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_2X8,
1932d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1942d7671f6SJacopo Mondi 		.bpp = 16,
1952d7671f6SJacopo Mondi 	}, {
1962d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_YUYV8_1X16,
1972d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
1982d7671f6SJacopo Mondi 		.bpp = 16,
1992d7671f6SJacopo Mondi 	}, {
2002d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
2012d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2022d7671f6SJacopo Mondi 		.bpp = 16,
2032d7671f6SJacopo Mondi 	}, {
2042d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
2052d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2062d7671f6SJacopo Mondi 		.bpp = 16,
2072d7671f6SJacopo Mondi 	}, {
2082d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SBGGR8_1X8,
2092d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2102d7671f6SJacopo Mondi 		.bpp = 8,
2112d7671f6SJacopo Mondi 	}, {
2122d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGBRG8_1X8,
2132d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2142d7671f6SJacopo Mondi 		.bpp = 8
2152d7671f6SJacopo Mondi 	}, {
2162d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SGRBG8_1X8,
2172d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2182d7671f6SJacopo Mondi 		.bpp = 8,
2192d7671f6SJacopo Mondi 	}, {
2202d7671f6SJacopo Mondi 		.code = MEDIA_BUS_FMT_SRGGB8_1X8,
2212d7671f6SJacopo Mondi 		.colorspace = V4L2_COLORSPACE_SRGB,
2222d7671f6SJacopo Mondi 		.bpp = 8,
2232d7671f6SJacopo Mondi 	},
224e3ee691dSHugues Fruchet };
225e3ee691dSHugues Fruchet 
2263c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code)
2273c28588fSJacopo Mondi {
2283c28588fSJacopo Mondi 	unsigned int i;
2293c28588fSJacopo Mondi 
2303c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) {
2313c28588fSJacopo Mondi 		if (ov5640_formats[i].code == code)
2323c28588fSJacopo Mondi 			return ov5640_formats[i].bpp;
2333c28588fSJacopo Mondi 	}
2343c28588fSJacopo Mondi 
2353c28588fSJacopo Mondi 	return 0;
2363c28588fSJacopo Mondi }
2373c28588fSJacopo Mondi 
23819a81c14SSteve Longerbeam /*
23919a81c14SSteve Longerbeam  * FIXME: remove this when a subdev API becomes available
24019a81c14SSteve Longerbeam  * to set the MIPI CSI-2 virtual channel.
24119a81c14SSteve Longerbeam  */
24219a81c14SSteve Longerbeam static unsigned int virtual_channel;
2438670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444);
24419a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel,
24519a81c14SSteve Longerbeam 		 "MIPI CSI-2 virtual channel (0..3), default 0");
24619a81c14SSteve Longerbeam 
24719a81c14SSteve Longerbeam static const int ov5640_framerates[] = {
24819a81c14SSteve Longerbeam 	[OV5640_15_FPS] = 15,
24919a81c14SSteve Longerbeam 	[OV5640_30_FPS] = 30,
250e823fb16SMaxime Ripard 	[OV5640_60_FPS] = 60,
25119a81c14SSteve Longerbeam };
25219a81c14SSteve Longerbeam 
25319a81c14SSteve Longerbeam /* regulator supplies */
25419a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = {
25541d8d7f5SHugues Fruchet 	"DOVDD", /* Digital I/O (1.8V) supply */
25619a81c14SSteve Longerbeam 	"AVDD",  /* Analog (2.8V) supply */
25724c8ac89SFabio Estevam 	"DVDD",  /* Digital Core (1.5V) supply */
25819a81c14SSteve Longerbeam };
25919a81c14SSteve Longerbeam 
26019a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name)
26119a81c14SSteve Longerbeam 
26219a81c14SSteve Longerbeam /*
26319a81c14SSteve Longerbeam  * Image size under 1280 * 960 are SUBSAMPLING
26419a81c14SSteve Longerbeam  * Image size upper 1280 * 960 are SCALING
26519a81c14SSteve Longerbeam  */
26619a81c14SSteve Longerbeam enum ov5640_downsize_mode {
26719a81c14SSteve Longerbeam 	SUBSAMPLING,
26819a81c14SSteve Longerbeam 	SCALING,
26919a81c14SSteve Longerbeam };
27019a81c14SSteve Longerbeam 
27119a81c14SSteve Longerbeam struct reg_value {
27219a81c14SSteve Longerbeam 	u16 reg_addr;
27319a81c14SSteve Longerbeam 	u8 val;
27419a81c14SSteve Longerbeam 	u8 mask;
27519a81c14SSteve Longerbeam 	u32 delay_ms;
27619a81c14SSteve Longerbeam };
27719a81c14SSteve Longerbeam 
27819a81c14SSteve Longerbeam struct ov5640_mode_info {
27919a81c14SSteve Longerbeam 	enum ov5640_mode_id id;
28019a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode;
28122845bf2SJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate;
282dba13a0bSMaxime Ripard 	u32 hact;
283476dec01SMaxime Ripard 	u32 htot;
284dba13a0bSMaxime Ripard 	u32 vact;
285476dec01SMaxime Ripard 	u32 vtot;
28619a81c14SSteve Longerbeam 	const struct reg_value *reg_data;
28719a81c14SSteve Longerbeam 	u32 reg_data_size;
2885554c80eSAdam Ford 	u32 max_fps;
28919a81c14SSteve Longerbeam };
29019a81c14SSteve Longerbeam 
29119a81c14SSteve Longerbeam struct ov5640_ctrls {
29219a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler handler;
293cc196e48SBenoit Parrot 	struct v4l2_ctrl *pixel_rate;
2947a3b8d4bSJacopo Mondi 	struct v4l2_ctrl *link_freq;
29519a81c14SSteve Longerbeam 	struct {
29619a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_exp;
29719a81c14SSteve Longerbeam 		struct v4l2_ctrl *exposure;
29819a81c14SSteve Longerbeam 	};
29919a81c14SSteve Longerbeam 	struct {
30019a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_wb;
30119a81c14SSteve Longerbeam 		struct v4l2_ctrl *blue_balance;
30219a81c14SSteve Longerbeam 		struct v4l2_ctrl *red_balance;
30319a81c14SSteve Longerbeam 	};
30419a81c14SSteve Longerbeam 	struct {
30519a81c14SSteve Longerbeam 		struct v4l2_ctrl *auto_gain;
30619a81c14SSteve Longerbeam 		struct v4l2_ctrl *gain;
30719a81c14SSteve Longerbeam 	};
30819a81c14SSteve Longerbeam 	struct v4l2_ctrl *brightness;
3091068fecaSMylène Josserand 	struct v4l2_ctrl *light_freq;
31019a81c14SSteve Longerbeam 	struct v4l2_ctrl *saturation;
31119a81c14SSteve Longerbeam 	struct v4l2_ctrl *contrast;
31219a81c14SSteve Longerbeam 	struct v4l2_ctrl *hue;
31319a81c14SSteve Longerbeam 	struct v4l2_ctrl *test_pattern;
314ce85705aSHugues Fruchet 	struct v4l2_ctrl *hflip;
315ce85705aSHugues Fruchet 	struct v4l2_ctrl *vflip;
31619a81c14SSteve Longerbeam };
31719a81c14SSteve Longerbeam 
31819a81c14SSteve Longerbeam struct ov5640_dev {
31919a81c14SSteve Longerbeam 	struct i2c_client *i2c_client;
32019a81c14SSteve Longerbeam 	struct v4l2_subdev sd;
32119a81c14SSteve Longerbeam 	struct media_pad pad;
32219a81c14SSteve Longerbeam 	struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */
32319a81c14SSteve Longerbeam 	struct clk *xclk; /* system clock to OV5640 */
32419a81c14SSteve Longerbeam 	u32 xclk_freq;
32519a81c14SSteve Longerbeam 
32619a81c14SSteve Longerbeam 	struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
32719a81c14SSteve Longerbeam 	struct gpio_desc *reset_gpio;
32819a81c14SSteve Longerbeam 	struct gpio_desc *pwdn_gpio;
329c3f3ba3eSHugues Fruchet 	bool   upside_down;
33019a81c14SSteve Longerbeam 
33119a81c14SSteve Longerbeam 	/* lock to protect all members below */
33219a81c14SSteve Longerbeam 	struct mutex lock;
33319a81c14SSteve Longerbeam 
33419a81c14SSteve Longerbeam 	int power_count;
33519a81c14SSteve Longerbeam 
33619a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt fmt;
337fb98e29fSHugues Fruchet 	bool pending_fmt_change;
33819a81c14SSteve Longerbeam 
33919a81c14SSteve Longerbeam 	const struct ov5640_mode_info *current_mode;
340985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *last_mode;
34119a81c14SSteve Longerbeam 	enum ov5640_frame_rate current_fr;
34219a81c14SSteve Longerbeam 	struct v4l2_fract frame_interval;
3433c28588fSJacopo Mondi 	s64 current_link_freq;
34419a81c14SSteve Longerbeam 
34519a81c14SSteve Longerbeam 	struct ov5640_ctrls ctrls;
34619a81c14SSteve Longerbeam 
34719a81c14SSteve Longerbeam 	u32 prev_sysclk, prev_hts;
34819a81c14SSteve Longerbeam 	u32 ae_low, ae_high, ae_target;
34919a81c14SSteve Longerbeam 
35019a81c14SSteve Longerbeam 	bool pending_mode_change;
35119a81c14SSteve Longerbeam 	bool streaming;
35219a81c14SSteve Longerbeam };
35319a81c14SSteve Longerbeam 
35419a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
35519a81c14SSteve Longerbeam {
35619a81c14SSteve Longerbeam 	return container_of(sd, struct ov5640_dev, sd);
35719a81c14SSteve Longerbeam }
35819a81c14SSteve Longerbeam 
35919a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
36019a81c14SSteve Longerbeam {
36119a81c14SSteve Longerbeam 	return &container_of(ctrl->handler, struct ov5640_dev,
36219a81c14SSteve Longerbeam 			     ctrls.handler)->sd;
36319a81c14SSteve Longerbeam }
36419a81c14SSteve Longerbeam 
3658e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
3668e823f5cSJacopo Mondi {
3678e823f5cSJacopo Mondi 	return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
3688e823f5cSJacopo Mondi }
3698e823f5cSJacopo Mondi 
37019a81c14SSteve Longerbeam /*
37119a81c14SSteve Longerbeam  * FIXME: all of these register tables are likely filled with
37219a81c14SSteve Longerbeam  * entries that set the register to their power-on default values,
37319a81c14SSteve Longerbeam  * and which are otherwise not touched by this driver. Those entries
37419a81c14SSteve Longerbeam  * should be identified and removed to speed register load time
37519a81c14SSteve Longerbeam  * over i2c.
37619a81c14SSteve Longerbeam  */
377fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */
37819a81c14SSteve Longerbeam static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
37919a81c14SSteve Longerbeam 	{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
380576f5d4bSLad Prabhakar 	{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
38119a81c14SSteve Longerbeam 	{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
38219a81c14SSteve Longerbeam 	{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
38319a81c14SSteve Longerbeam 	{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
38419a81c14SSteve Longerbeam 	{0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0},
38519a81c14SSteve Longerbeam 	{0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0},
38619a81c14SSteve Longerbeam 	{0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0},
38719a81c14SSteve Longerbeam 	{0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0},
38819a81c14SSteve Longerbeam 	{0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0},
38919a81c14SSteve Longerbeam 	{0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0},
39019a81c14SSteve Longerbeam 	{0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0},
39119a81c14SSteve Longerbeam 	{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
39219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
39319a81c14SSteve Longerbeam 	{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
39419a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
39519a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
39619a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
397476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
39819a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
39919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
40019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
40119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
40219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
40319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
40419a81c14SSteve Longerbeam 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0},
40519a81c14SSteve Longerbeam 	{0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0},
406aa4bb8b8SJacopo Mondi 	{0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0},
4072b5c18f9SChen-Yu Tsai 	{0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0},
40819a81c14SSteve Longerbeam 	{0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
409aa4bb8b8SJacopo Mondi 	{0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0},
41019a81c14SSteve Longerbeam 	{0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0},
41119a81c14SSteve Longerbeam 	{0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0},
41219a81c14SSteve Longerbeam 	{0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0},
41319a81c14SSteve Longerbeam 	{0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0},
41419a81c14SSteve Longerbeam 	{0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0},
41519a81c14SSteve Longerbeam 	{0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0},
41619a81c14SSteve Longerbeam 	{0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0},
41719a81c14SSteve Longerbeam 	{0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0},
41819a81c14SSteve Longerbeam 	{0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0},
41919a81c14SSteve Longerbeam 	{0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0},
42019a81c14SSteve Longerbeam 	{0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0},
42119a81c14SSteve Longerbeam 	{0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0},
42219a81c14SSteve Longerbeam 	{0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0},
42319a81c14SSteve Longerbeam 	{0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0},
42419a81c14SSteve Longerbeam 	{0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0},
42519a81c14SSteve Longerbeam 	{0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0},
42619a81c14SSteve Longerbeam 	{0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0},
42719a81c14SSteve Longerbeam 	{0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0},
42819a81c14SSteve Longerbeam 	{0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0},
42919a81c14SSteve Longerbeam 	{0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0},
43019a81c14SSteve Longerbeam 	{0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0},
43119a81c14SSteve Longerbeam 	{0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0},
43219a81c14SSteve Longerbeam 	{0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0},
43319a81c14SSteve Longerbeam 	{0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0},
43419a81c14SSteve Longerbeam 	{0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0},
43519a81c14SSteve Longerbeam 	{0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0},
43619a81c14SSteve Longerbeam 	{0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0},
43719a81c14SSteve Longerbeam 	{0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0},
43819a81c14SSteve Longerbeam 	{0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0},
43919a81c14SSteve Longerbeam 	{0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0},
44019a81c14SSteve Longerbeam 	{0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0},
44119a81c14SSteve Longerbeam 	{0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0},
44219a81c14SSteve Longerbeam 	{0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0},
44319a81c14SSteve Longerbeam 	{0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0},
44419a81c14SSteve Longerbeam 	{0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0},
44519a81c14SSteve Longerbeam 	{0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0},
44619a81c14SSteve Longerbeam 	{0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0},
44719a81c14SSteve Longerbeam 	{0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0},
44819a81c14SSteve Longerbeam 	{0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0},
44919a81c14SSteve Longerbeam 	{0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0},
45019a81c14SSteve Longerbeam 	{0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0},
45119a81c14SSteve Longerbeam 	{0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0},
45219a81c14SSteve Longerbeam 	{0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0},
45319a81c14SSteve Longerbeam 	{0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0},
45419a81c14SSteve Longerbeam 	{0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0},
45519a81c14SSteve Longerbeam 	{0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0},
45619a81c14SSteve Longerbeam 	{0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0},
45719a81c14SSteve Longerbeam 	{0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0},
45819a81c14SSteve Longerbeam 	{0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0},
45919a81c14SSteve Longerbeam 	{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
46019a81c14SSteve Longerbeam };
46119a81c14SSteve Longerbeam 
462086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_VGA_640_480[] = {
463c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
46419a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
465ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
46619a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
46719a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
46819a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
469476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
47019a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
47119a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
47219a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
47319a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
47419a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
47519a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4762b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
47719a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
47819a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
47919a81c14SSteve Longerbeam };
48019a81c14SSteve Longerbeam 
481086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_XGA_1024_768[] = {
482c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
48319a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
484ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
48519a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
48619a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
48719a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
488476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
48919a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
49019a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
49119a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
49219a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
49319a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
49419a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
4952b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
49619a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
49786633417SMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
49819a81c14SSteve Longerbeam };
49919a81c14SSteve Longerbeam 
500086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QVGA_320_240[] = {
501c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
50219a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
503ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
50419a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
50519a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
50619a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
507476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
50819a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
50919a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
51019a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
51119a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
51219a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
51319a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5142b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
51519a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
51619a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
51719a81c14SSteve Longerbeam };
51819a81c14SSteve Longerbeam 
51932ea5e05SHugues Fruchet static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
52032ea5e05SHugues Fruchet 	{0x3c07, 0x08, 0, 0},
52132ea5e05SHugues Fruchet 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
52232ea5e05SHugues Fruchet 	{0x3814, 0x31, 0, 0},
52332ea5e05SHugues Fruchet 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
52432ea5e05SHugues Fruchet 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
52532ea5e05SHugues Fruchet 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
52632ea5e05SHugues Fruchet 	{0x3810, 0x00, 0, 0},
52732ea5e05SHugues Fruchet 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
52832ea5e05SHugues Fruchet 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
52932ea5e05SHugues Fruchet 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
53032ea5e05SHugues Fruchet 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
53132ea5e05SHugues Fruchet 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
53232ea5e05SHugues Fruchet 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
53332ea5e05SHugues Fruchet 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
53432ea5e05SHugues Fruchet 	{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
53532ea5e05SHugues Fruchet };
53632ea5e05SHugues Fruchet 
537086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QCIF_176_144[] = {
538c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
53919a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
540ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
54119a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
54219a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
54319a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
544476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
54519a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
54619a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
54719a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
54819a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
54919a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
55019a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5512b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
55219a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
55319a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
55419a81c14SSteve Longerbeam };
55519a81c14SSteve Longerbeam 
556086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_NTSC_720_480[] = {
557c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
55819a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
559ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
56019a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
56119a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
56219a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
563476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
56419a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
56519a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
56619a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
56719a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
56819a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
56919a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5702b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
57119a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
57219a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
57319a81c14SSteve Longerbeam };
57419a81c14SSteve Longerbeam 
575086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_PAL_720_576[] = {
576c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
57719a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
578ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
57919a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
58019a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
58119a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
582476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
58319a81c14SSteve Longerbeam 	{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
58419a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
58519a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
58619a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
58719a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
58819a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
5892b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
59019a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
59119a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
59219a81c14SSteve Longerbeam };
59319a81c14SSteve Longerbeam 
594086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = {
595c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0},
59619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
597ce85705aSHugues Fruchet 	{0x3814, 0x31, 0, 0},
59819a81c14SSteve Longerbeam 	{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
59919a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
60019a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
601476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
60219a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
60319a81c14SSteve Longerbeam 	{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
60419a81c14SSteve Longerbeam 	{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
60519a81c14SSteve Longerbeam 	{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
60619a81c14SSteve Longerbeam 	{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
60719a81c14SSteve Longerbeam 	{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
6082b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
60919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
61019a81c14SSteve Longerbeam 	{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
61119a81c14SSteve Longerbeam };
61219a81c14SSteve Longerbeam 
613086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
614c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
61519a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
616ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
61719a81c14SSteve Longerbeam 	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
61819a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
61919a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
620476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
62119a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
62219a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
62319a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
62419a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
62519a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
62619a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6272b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
62819a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
629c14d107eSMaxime Ripard 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
630c14d107eSMaxime Ripard 	{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
63119a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
63219a81c14SSteve Longerbeam 	{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
63319a81c14SSteve Longerbeam 	{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
63486633417SMaxime Ripard 	{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
635476dec01SMaxime Ripard 	{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
63619a81c14SSteve Longerbeam 	{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
63719a81c14SSteve Longerbeam 	{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
63819a81c14SSteve Longerbeam 	{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
6392b5c18f9SChen-Yu Tsai 	{0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0},
64019a81c14SSteve Longerbeam 	{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
64192b9096cSBenoit Parrot 	{0x4005, 0x1a, 0, 0},
64219a81c14SSteve Longerbeam };
64319a81c14SSteve Longerbeam 
644086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
645c14d107eSMaxime Ripard 	{0x3c07, 0x08, 0, 0},
64619a81c14SSteve Longerbeam 	{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
647ce85705aSHugues Fruchet 	{0x3814, 0x11, 0, 0},
64819a81c14SSteve Longerbeam 	{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
64919a81c14SSteve Longerbeam 	{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
65019a81c14SSteve Longerbeam 	{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
651476dec01SMaxime Ripard 	{0x3810, 0x00, 0, 0},
65219a81c14SSteve Longerbeam 	{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
65319a81c14SSteve Longerbeam 	{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
65419a81c14SSteve Longerbeam 	{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
65519a81c14SSteve Longerbeam 	{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
65619a81c14SSteve Longerbeam 	{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
65719a81c14SSteve Longerbeam 	{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
6582b5c18f9SChen-Yu Tsai 	{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0},
65919a81c14SSteve Longerbeam 	{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
66019a81c14SSteve Longerbeam 	{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
66119a81c14SSteve Longerbeam };
66219a81c14SSteve Longerbeam 
66319a81c14SSteve Longerbeam /* power-on sensor init reg table */
66419a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = {
66522845bf2SJacopo Mondi 	0, SUBSAMPLING,
66622845bf2SJacopo Mondi 	OV5640_PIXEL_RATE_96M,
66722845bf2SJacopo Mondi 	640, 1896, 480, 984,
668476dec01SMaxime Ripard 	ov5640_init_setting_30fps_VGA,
66919a81c14SSteve Longerbeam 	ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
6705554c80eSAdam Ford 	OV5640_30_FPS,
67119a81c14SSteve Longerbeam };
67219a81c14SSteve Longerbeam 
67319a81c14SSteve Longerbeam static const struct ov5640_mode_info
674086c25f8SMaxime Ripard ov5640_mode_data[OV5640_NUM_MODES] = {
6758409d017SJacopo Mondi 	{
6768409d017SJacopo Mondi 		/* 160x120 */
6778409d017SJacopo Mondi 		OV5640_MODE_QQVGA_160_120, SUBSAMPLING,
67822845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
67932ea5e05SHugues Fruchet 		160, 1896, 120, 984,
68032ea5e05SHugues Fruchet 		ov5640_setting_QQVGA_160_120,
68132ea5e05SHugues Fruchet 		ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
6828409d017SJacopo Mondi 		OV5640_30_FPS
6838409d017SJacopo Mondi 	}, {
6848409d017SJacopo Mondi 		/* 176x144 */
6858409d017SJacopo Mondi 		OV5640_MODE_QCIF_176_144, SUBSAMPLING,
68622845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
687476dec01SMaxime Ripard 		176, 1896, 144, 984,
688086c25f8SMaxime Ripard 		ov5640_setting_QCIF_176_144,
6895554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_QCIF_176_144),
6908409d017SJacopo Mondi 		OV5640_30_FPS
6918409d017SJacopo Mondi 	}, {
6928409d017SJacopo Mondi 		/* 320x240 */
6938409d017SJacopo Mondi 		OV5640_MODE_QVGA_320_240, SUBSAMPLING,
69422845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
695476dec01SMaxime Ripard 		320, 1896, 240, 984,
696086c25f8SMaxime Ripard 		ov5640_setting_QVGA_320_240,
6975554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_QVGA_320_240),
6988409d017SJacopo Mondi 		OV5640_30_FPS
6998409d017SJacopo Mondi 	}, {
7008409d017SJacopo Mondi 		/* 640x480 */
7018409d017SJacopo Mondi 		OV5640_MODE_VGA_640_480, SUBSAMPLING,
70222845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_48M,
703476dec01SMaxime Ripard 		640, 1896, 480, 1080,
704086c25f8SMaxime Ripard 		ov5640_setting_VGA_640_480,
7055554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_VGA_640_480),
7068409d017SJacopo Mondi 		OV5640_60_FPS
7078409d017SJacopo Mondi 	}, {
7088409d017SJacopo Mondi 		/* 720x480 */
7098409d017SJacopo Mondi 		OV5640_MODE_NTSC_720_480, SUBSAMPLING,
71022845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_96M,
711476dec01SMaxime Ripard 		720, 1896, 480, 984,
712086c25f8SMaxime Ripard 		ov5640_setting_NTSC_720_480,
7135554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_NTSC_720_480),
7148409d017SJacopo Mondi 		OV5640_30_FPS
7158409d017SJacopo Mondi 	}, {
7168409d017SJacopo Mondi 		/* 720x576 */
7178409d017SJacopo Mondi 		OV5640_MODE_PAL_720_576, SUBSAMPLING,
71822845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_96M,
719476dec01SMaxime Ripard 		720, 1896, 576, 984,
720086c25f8SMaxime Ripard 		ov5640_setting_PAL_720_576,
7215554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_PAL_720_576),
7228409d017SJacopo Mondi 		OV5640_30_FPS
7238409d017SJacopo Mondi 	}, {
7248409d017SJacopo Mondi 		/* 1024x768 */
7258409d017SJacopo Mondi 		OV5640_MODE_XGA_1024_768, SUBSAMPLING,
72622845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_96M,
727476dec01SMaxime Ripard 		1024, 1896, 768, 1080,
728086c25f8SMaxime Ripard 		ov5640_setting_XGA_1024_768,
7295554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_XGA_1024_768),
7308409d017SJacopo Mondi 		OV5640_30_FPS
7318409d017SJacopo Mondi 	}, {
7328409d017SJacopo Mondi 		/* 1280x720 */
7338409d017SJacopo Mondi 		OV5640_MODE_720P_1280_720, SUBSAMPLING,
73422845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_124M,
735476dec01SMaxime Ripard 		1280, 1892, 720, 740,
736086c25f8SMaxime Ripard 		ov5640_setting_720P_1280_720,
7375554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_720P_1280_720),
7388409d017SJacopo Mondi 		OV5640_30_FPS
7398409d017SJacopo Mondi 	}, {
7408409d017SJacopo Mondi 		/* 1920x1080 */
7418409d017SJacopo Mondi 		OV5640_MODE_1080P_1920_1080, SCALING,
74222845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_148M,
743476dec01SMaxime Ripard 		1920, 2500, 1080, 1120,
744086c25f8SMaxime Ripard 		ov5640_setting_1080P_1920_1080,
7455554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
7468409d017SJacopo Mondi 		OV5640_30_FPS
7478409d017SJacopo Mondi 	}, {
7488409d017SJacopo Mondi 		/* 2592x1944 */
7498409d017SJacopo Mondi 		OV5640_MODE_QSXGA_2592_1944, SCALING,
75022845bf2SJacopo Mondi 		OV5640_PIXEL_RATE_168M,
751476dec01SMaxime Ripard 		2592, 2844, 1944, 1968,
752086c25f8SMaxime Ripard 		ov5640_setting_QSXGA_2592_1944,
7535554c80eSAdam Ford 		ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
7548409d017SJacopo Mondi 		OV5640_15_FPS
7558409d017SJacopo Mondi 	},
75619a81c14SSteve Longerbeam };
75719a81c14SSteve Longerbeam 
75819a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor)
75919a81c14SSteve Longerbeam {
76019a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
76119a81c14SSteve Longerbeam 	struct i2c_msg msg;
76219a81c14SSteve Longerbeam 	u8 buf[3];
76319a81c14SSteve Longerbeam 	int ret;
76419a81c14SSteve Longerbeam 
76519a81c14SSteve Longerbeam 	if (client->addr == OV5640_DEFAULT_SLAVE_ID)
76619a81c14SSteve Longerbeam 		return 0;
76719a81c14SSteve Longerbeam 
76819a81c14SSteve Longerbeam 	buf[0] = OV5640_REG_SLAVE_ID >> 8;
76919a81c14SSteve Longerbeam 	buf[1] = OV5640_REG_SLAVE_ID & 0xff;
77019a81c14SSteve Longerbeam 	buf[2] = client->addr << 1;
77119a81c14SSteve Longerbeam 
77219a81c14SSteve Longerbeam 	msg.addr = OV5640_DEFAULT_SLAVE_ID;
77319a81c14SSteve Longerbeam 	msg.flags = 0;
77419a81c14SSteve Longerbeam 	msg.buf = buf;
77519a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
77619a81c14SSteve Longerbeam 
77719a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
77819a81c14SSteve Longerbeam 	if (ret < 0) {
77919a81c14SSteve Longerbeam 		dev_err(&client->dev, "%s: failed with %d\n", __func__, ret);
78019a81c14SSteve Longerbeam 		return ret;
78119a81c14SSteve Longerbeam 	}
78219a81c14SSteve Longerbeam 
78319a81c14SSteve Longerbeam 	return 0;
78419a81c14SSteve Longerbeam }
78519a81c14SSteve Longerbeam 
78619a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val)
78719a81c14SSteve Longerbeam {
78819a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
78919a81c14SSteve Longerbeam 	struct i2c_msg msg;
79019a81c14SSteve Longerbeam 	u8 buf[3];
79119a81c14SSteve Longerbeam 	int ret;
79219a81c14SSteve Longerbeam 
79319a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
79419a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
79519a81c14SSteve Longerbeam 	buf[2] = val;
79619a81c14SSteve Longerbeam 
79719a81c14SSteve Longerbeam 	msg.addr = client->addr;
79819a81c14SSteve Longerbeam 	msg.flags = client->flags;
79919a81c14SSteve Longerbeam 	msg.buf = buf;
80019a81c14SSteve Longerbeam 	msg.len = sizeof(buf);
80119a81c14SSteve Longerbeam 
80219a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, &msg, 1);
80319a81c14SSteve Longerbeam 	if (ret < 0) {
8043924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x, val=%x\n",
80519a81c14SSteve Longerbeam 			__func__, reg, val);
80619a81c14SSteve Longerbeam 		return ret;
80719a81c14SSteve Longerbeam 	}
80819a81c14SSteve Longerbeam 
80919a81c14SSteve Longerbeam 	return 0;
81019a81c14SSteve Longerbeam }
81119a81c14SSteve Longerbeam 
81219a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val)
81319a81c14SSteve Longerbeam {
81419a81c14SSteve Longerbeam 	struct i2c_client *client = sensor->i2c_client;
81519a81c14SSteve Longerbeam 	struct i2c_msg msg[2];
81619a81c14SSteve Longerbeam 	u8 buf[2];
81719a81c14SSteve Longerbeam 	int ret;
81819a81c14SSteve Longerbeam 
81919a81c14SSteve Longerbeam 	buf[0] = reg >> 8;
82019a81c14SSteve Longerbeam 	buf[1] = reg & 0xff;
82119a81c14SSteve Longerbeam 
82219a81c14SSteve Longerbeam 	msg[0].addr = client->addr;
82319a81c14SSteve Longerbeam 	msg[0].flags = client->flags;
82419a81c14SSteve Longerbeam 	msg[0].buf = buf;
82519a81c14SSteve Longerbeam 	msg[0].len = sizeof(buf);
82619a81c14SSteve Longerbeam 
82719a81c14SSteve Longerbeam 	msg[1].addr = client->addr;
82819a81c14SSteve Longerbeam 	msg[1].flags = client->flags | I2C_M_RD;
82919a81c14SSteve Longerbeam 	msg[1].buf = buf;
83019a81c14SSteve Longerbeam 	msg[1].len = 1;
83119a81c14SSteve Longerbeam 
83219a81c14SSteve Longerbeam 	ret = i2c_transfer(client->adapter, msg, 2);
8333924c623SHugues Fruchet 	if (ret < 0) {
8343924c623SHugues Fruchet 		dev_err(&client->dev, "%s: error: reg=%x\n",
8353924c623SHugues Fruchet 			__func__, reg);
83619a81c14SSteve Longerbeam 		return ret;
8373924c623SHugues Fruchet 	}
83819a81c14SSteve Longerbeam 
83919a81c14SSteve Longerbeam 	*val = buf[0];
84019a81c14SSteve Longerbeam 	return 0;
84119a81c14SSteve Longerbeam }
84219a81c14SSteve Longerbeam 
84319a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val)
84419a81c14SSteve Longerbeam {
84519a81c14SSteve Longerbeam 	u8 hi, lo;
84619a81c14SSteve Longerbeam 	int ret;
84719a81c14SSteve Longerbeam 
84819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &hi);
84919a81c14SSteve Longerbeam 	if (ret)
85019a81c14SSteve Longerbeam 		return ret;
85119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg + 1, &lo);
85219a81c14SSteve Longerbeam 	if (ret)
85319a81c14SSteve Longerbeam 		return ret;
85419a81c14SSteve Longerbeam 
85519a81c14SSteve Longerbeam 	*val = ((u16)hi << 8) | (u16)lo;
85619a81c14SSteve Longerbeam 	return 0;
85719a81c14SSteve Longerbeam }
85819a81c14SSteve Longerbeam 
85919a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val)
86019a81c14SSteve Longerbeam {
86119a81c14SSteve Longerbeam 	int ret;
86219a81c14SSteve Longerbeam 
86319a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, reg, val >> 8);
86419a81c14SSteve Longerbeam 	if (ret)
86519a81c14SSteve Longerbeam 		return ret;
86619a81c14SSteve Longerbeam 
86719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg + 1, val & 0xff);
86819a81c14SSteve Longerbeam }
86919a81c14SSteve Longerbeam 
87019a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
87119a81c14SSteve Longerbeam 			  u8 mask, u8 val)
87219a81c14SSteve Longerbeam {
87319a81c14SSteve Longerbeam 	u8 readval;
87419a81c14SSteve Longerbeam 	int ret;
87519a81c14SSteve Longerbeam 
87619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, reg, &readval);
87719a81c14SSteve Longerbeam 	if (ret)
87819a81c14SSteve Longerbeam 		return ret;
87919a81c14SSteve Longerbeam 
88019a81c14SSteve Longerbeam 	readval &= ~mask;
88119a81c14SSteve Longerbeam 	val &= mask;
88219a81c14SSteve Longerbeam 	val |= readval;
88319a81c14SSteve Longerbeam 
88419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, reg, val);
88519a81c14SSteve Longerbeam }
88619a81c14SSteve Longerbeam 
887aa288248SMaxime Ripard /*
888aa288248SMaxime Ripard  * After trying the various combinations, reading various
889f8a7647dSMauro Carvalho Chehab  * documentations spread around the net, and from the various
890aa288248SMaxime Ripard  * feedback, the clock tree is probably as follows:
891aa288248SMaxime Ripard  *
892aa288248SMaxime Ripard  *   +--------------+
893aa288248SMaxime Ripard  *   |  Ext. Clock  |
894aa288248SMaxime Ripard  *   +-+------------+
895aa288248SMaxime Ripard  *     |  +----------+
896aa288248SMaxime Ripard  *     +->|   PLL1   | - reg 0x3036, for the multiplier
897aa288248SMaxime Ripard  *        +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
898aa288248SMaxime Ripard  *          |  +--------------+
899aa288248SMaxime Ripard  *          +->| System Clock |  - reg 0x3035, bits 4-7
900aa288248SMaxime Ripard  *             +-+------------+
901aa288248SMaxime Ripard  *               |  +--------------+
902aa288248SMaxime Ripard  *               +->| MIPI Divider | - reg 0x3035, bits 0-3
903aa288248SMaxime Ripard  *               |  +-+------------+
904aa288248SMaxime Ripard  *               |    +----------------> MIPI SCLK
905aa288248SMaxime Ripard  *               |    +  +-----+
906aa288248SMaxime Ripard  *               |    +->| / 2 |-------> MIPI BIT CLK
907aa288248SMaxime Ripard  *               |       +-----+
908aa288248SMaxime Ripard  *               |  +--------------+
909aa288248SMaxime Ripard  *               +->| PLL Root Div | - reg 0x3037, bit 4
910aa288248SMaxime Ripard  *                  +-+------------+
911aa288248SMaxime Ripard  *                    |  +---------+
9124c85f628SPaul Kocialkowski  *                    +->| Bit Div | - reg 0x3034, bits 0-3
913aa288248SMaxime Ripard  *                       +-+-------+
914aa288248SMaxime Ripard  *                         |  +-------------+
915aa288248SMaxime Ripard  *                         +->| SCLK Div    | - reg 0x3108, bits 0-1
916aa288248SMaxime Ripard  *                         |  +-+-----------+
917aa288248SMaxime Ripard  *                         |    +---------------> SCLK
918aa288248SMaxime Ripard  *                         |  +-------------+
919aa288248SMaxime Ripard  *                         +->| SCLK 2X Div | - reg 0x3108, bits 2-3
920aa288248SMaxime Ripard  *                         |  +-+-----------+
921aa288248SMaxime Ripard  *                         |    +---------------> SCLK 2X
922aa288248SMaxime Ripard  *                         |  +-------------+
923aa288248SMaxime Ripard  *                         +->| PCLK Div    | - reg 0x3108, bits 4-5
924aa288248SMaxime Ripard  *                            ++------------+
925aa288248SMaxime Ripard  *                             +  +-----------+
926aa288248SMaxime Ripard  *                             +->|   P_DIV   | - reg 0x3035, bits 0-3
927aa288248SMaxime Ripard  *                                +-----+-----+
928aa288248SMaxime Ripard  *                                       +------------> PCLK
929aa288248SMaxime Ripard  *
930*6c957ed7SJacopo Mondi  * There seems to be also constraints:
931aa288248SMaxime Ripard  *  - the PLL pre-divider output rate should be in the 4-27MHz range
932aa288248SMaxime Ripard  *  - the PLL multiplier output rate should be in the 500-1000MHz range
933aa288248SMaxime Ripard  *  - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
934aa288248SMaxime Ripard  */
935aa288248SMaxime Ripard 
936aa288248SMaxime Ripard /*
937aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
938aa288248SMaxime Ripard  * set to 3 in the vendor kernels.
939aa288248SMaxime Ripard  */
940aa288248SMaxime Ripard #define OV5640_PLL_PREDIV	3
941aa288248SMaxime Ripard 
942aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN	4
943aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX	252
944aa288248SMaxime Ripard 
945aa288248SMaxime Ripard /*
946aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 16, but the value is
947aa288248SMaxime Ripard  * always set to either 1 or 2 in the vendor kernels.
948aa288248SMaxime Ripard  */
949aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN	1
950aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX	16
951aa288248SMaxime Ripard 
952aa288248SMaxime Ripard /*
953aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 2, but the value is always
954aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
955aa288248SMaxime Ripard  */
956aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV			2
957aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2		BIT(4)
958aa288248SMaxime Ripard 
959aa288248SMaxime Ripard /*
960aa288248SMaxime Ripard  * We only supports 8-bit formats at the moment
961aa288248SMaxime Ripard  */
962aa288248SMaxime Ripard #define OV5640_BIT_DIV				2
963aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT		0x08
964aa288248SMaxime Ripard 
965aa288248SMaxime Ripard /*
966aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
967aa288248SMaxime Ripard  * set to 2 in the vendor kernels.
968aa288248SMaxime Ripard  */
969aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV	2
970aa288248SMaxime Ripard 
971aa288248SMaxime Ripard /*
972aa288248SMaxime Ripard  * This is hardcoded so that the consistency is maintained between SCLK and
973aa288248SMaxime Ripard  * SCLK 2x.
974aa288248SMaxime Ripard  */
975aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
976aa288248SMaxime Ripard 
977aa288248SMaxime Ripard /*
978aa288248SMaxime Ripard  * This is supposed to be ranging from 1 to 8, but the value is always
979aa288248SMaxime Ripard  * set to 1 in the vendor kernels.
980aa288248SMaxime Ripard  */
981aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV			1
982aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS	0x00
983aa288248SMaxime Ripard 
984aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
985aa288248SMaxime Ripard 					    u8 pll_prediv, u8 pll_mult,
986aa288248SMaxime Ripard 					    u8 sysdiv)
987aa288248SMaxime Ripard {
988aa288248SMaxime Ripard 	unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
989aa288248SMaxime Ripard 
990aa288248SMaxime Ripard 	/* PLL1 output cannot exceed 1GHz. */
991aa288248SMaxime Ripard 	if (sysclk / 1000000 > 1000)
992aa288248SMaxime Ripard 		return 0;
993aa288248SMaxime Ripard 
994aa288248SMaxime Ripard 	return sysclk / sysdiv;
995aa288248SMaxime Ripard }
996aa288248SMaxime Ripard 
997aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
998aa288248SMaxime Ripard 					 unsigned long rate,
999aa288248SMaxime Ripard 					 u8 *pll_prediv, u8 *pll_mult,
1000aa288248SMaxime Ripard 					 u8 *sysdiv)
1001aa288248SMaxime Ripard {
1002aa288248SMaxime Ripard 	unsigned long best = ~0;
1003aa288248SMaxime Ripard 	u8 best_sysdiv = 1, best_mult = 1;
1004aa288248SMaxime Ripard 	u8 _sysdiv, _pll_mult;
1005aa288248SMaxime Ripard 
1006aa288248SMaxime Ripard 	for (_sysdiv = OV5640_SYSDIV_MIN;
1007aa288248SMaxime Ripard 	     _sysdiv <= OV5640_SYSDIV_MAX;
1008aa288248SMaxime Ripard 	     _sysdiv++) {
1009aa288248SMaxime Ripard 		for (_pll_mult = OV5640_PLL_MULT_MIN;
1010aa288248SMaxime Ripard 		     _pll_mult <= OV5640_PLL_MULT_MAX;
1011aa288248SMaxime Ripard 		     _pll_mult++) {
1012aa288248SMaxime Ripard 			unsigned long _rate;
1013aa288248SMaxime Ripard 
1014aa288248SMaxime Ripard 			/*
1015aa288248SMaxime Ripard 			 * The PLL multiplier cannot be odd if above
1016aa288248SMaxime Ripard 			 * 127.
1017aa288248SMaxime Ripard 			 */
1018aa288248SMaxime Ripard 			if (_pll_mult > 127 && (_pll_mult % 2))
1019aa288248SMaxime Ripard 				continue;
1020aa288248SMaxime Ripard 
1021aa288248SMaxime Ripard 			_rate = ov5640_compute_sys_clk(sensor,
1022aa288248SMaxime Ripard 						       OV5640_PLL_PREDIV,
1023aa288248SMaxime Ripard 						       _pll_mult, _sysdiv);
1024aa288248SMaxime Ripard 
1025aa288248SMaxime Ripard 			/*
1026aa288248SMaxime Ripard 			 * We have reached the maximum allowed PLL1 output,
1027aa288248SMaxime Ripard 			 * increase sysdiv.
1028aa288248SMaxime Ripard 			 */
10292e3df204SAdam Ford 			if (!_rate)
1030aa288248SMaxime Ripard 				break;
1031aa288248SMaxime Ripard 
1032aa288248SMaxime Ripard 			/*
1033aa288248SMaxime Ripard 			 * Prefer rates above the expected clock rate than
1034aa288248SMaxime Ripard 			 * below, even if that means being less precise.
1035aa288248SMaxime Ripard 			 */
1036aa288248SMaxime Ripard 			if (_rate < rate)
1037aa288248SMaxime Ripard 				continue;
1038aa288248SMaxime Ripard 
1039aa288248SMaxime Ripard 			if (abs(rate - _rate) < abs(rate - best)) {
1040aa288248SMaxime Ripard 				best = _rate;
1041aa288248SMaxime Ripard 				best_sysdiv = _sysdiv;
1042aa288248SMaxime Ripard 				best_mult = _pll_mult;
1043aa288248SMaxime Ripard 			}
1044aa288248SMaxime Ripard 
1045aa288248SMaxime Ripard 			if (_rate == rate)
1046aa288248SMaxime Ripard 				goto out;
1047aa288248SMaxime Ripard 		}
1048aa288248SMaxime Ripard 	}
1049aa288248SMaxime Ripard 
1050aa288248SMaxime Ripard out:
1051aa288248SMaxime Ripard 	*sysdiv = best_sysdiv;
1052aa288248SMaxime Ripard 	*pll_prediv = OV5640_PLL_PREDIV;
1053aa288248SMaxime Ripard 	*pll_mult = best_mult;
1054aa288248SMaxime Ripard 
1055aa288248SMaxime Ripard 	return best;
1056aa288248SMaxime Ripard }
1057aa288248SMaxime Ripard 
1058aa288248SMaxime Ripard /*
1059aa288248SMaxime Ripard  * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
1060aa288248SMaxime Ripard  *			    for the MIPI CSI-2 output.
1061aa288248SMaxime Ripard  */
1062*6c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
1063aa288248SMaxime Ripard {
1064*6c957ed7SJacopo Mondi 	u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
1065aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv;
1066*6c957ed7SJacopo Mondi 	unsigned long link_freq;
1067*6c957ed7SJacopo Mondi 	unsigned long sysclk;
1068*6c957ed7SJacopo Mondi 	u8 pclk_period;
1069*6c957ed7SJacopo Mondi 	u32 sample_rate;
1070*6c957ed7SJacopo Mondi 	u32 num_lanes;
1071aa288248SMaxime Ripard 	int ret;
1072aa288248SMaxime Ripard 
1073*6c957ed7SJacopo Mondi 	/* Use the link freq computed at ov5640_update_pixel_rate() time. */
1074*6c957ed7SJacopo Mondi 	link_freq = sensor->current_link_freq;
1075*6c957ed7SJacopo Mondi 
1076aa288248SMaxime Ripard 	/*
1077*6c957ed7SJacopo Mondi 	 * - mipi_div - Additional divider for the MIPI lane clock.
1078*6c957ed7SJacopo Mondi 	 *
1079*6c957ed7SJacopo Mondi 	 * Higher link frequencies would make sysclk > 1GHz.
1080*6c957ed7SJacopo Mondi 	 * Keep the sysclk low and do not divide in the MIPI domain.
1081aa288248SMaxime Ripard 	 */
1082*6c957ed7SJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX)
1083*6c957ed7SJacopo Mondi 		mipi_div = 1;
1084aa288248SMaxime Ripard 	else
1085*6c957ed7SJacopo Mondi 		mipi_div = 2;
1086aa288248SMaxime Ripard 
1087*6c957ed7SJacopo Mondi 	sysclk = link_freq * mipi_div;
1088*6c957ed7SJacopo Mondi 	ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
1089aa288248SMaxime Ripard 
1090*6c957ed7SJacopo Mondi 	/*
1091*6c957ed7SJacopo Mondi 	 * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
1092*6c957ed7SJacopo Mondi 	 *
1093*6c957ed7SJacopo Mondi 	 * - root_div = 2 (fixed)
1094*6c957ed7SJacopo Mondi 	 * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
1095*6c957ed7SJacopo Mondi 	 * - pclk_div = 1 (fixed)
1096*6c957ed7SJacopo Mondi 	 * - p_div  = (2 lanes ? mipi_div : 2 * mipi_div)
1097*6c957ed7SJacopo Mondi 	 *
1098*6c957ed7SJacopo Mondi 	 * This results in the following MIPI_SCLK depending on the number
1099*6c957ed7SJacopo Mondi 	 * of lanes:
1100*6c957ed7SJacopo Mondi 	 *
1101*6c957ed7SJacopo Mondi 	 * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
1102*6c957ed7SJacopo Mondi 	 * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
1103*6c957ed7SJacopo Mondi 	 */
1104*6c957ed7SJacopo Mondi 	root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
1105*6c957ed7SJacopo Mondi 	bit_div =  OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
1106*6c957ed7SJacopo Mondi 	pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
1107aa288248SMaxime Ripard 
1108*6c957ed7SJacopo Mondi 	/*
1109*6c957ed7SJacopo Mondi 	 * Scaler clock:
1110*6c957ed7SJacopo Mondi 	 * - YUV: PCLK >= 2 * SCLK
1111*6c957ed7SJacopo Mondi 	 * - RAW or JPEG: PCLK >= SCLK
1112*6c957ed7SJacopo Mondi 	 * - sclk2x_div = sclk_div / 2
1113*6c957ed7SJacopo Mondi 	 */
1114*6c957ed7SJacopo Mondi 	sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
1115*6c957ed7SJacopo Mondi 	sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
1116*6c957ed7SJacopo Mondi 
1117*6c957ed7SJacopo Mondi 	/*
1118*6c957ed7SJacopo Mondi 	 * Set the pixel clock period expressed in ns with 1-bit decimal
1119*6c957ed7SJacopo Mondi 	 * (0x01=0.5ns).
1120*6c957ed7SJacopo Mondi 	 *
1121*6c957ed7SJacopo Mondi 	 * The register is very briefly documented. In the OV5645 datasheet it
1122*6c957ed7SJacopo Mondi 	 * is described as (2 * pclk period), and from testing it seems the
1123*6c957ed7SJacopo Mondi 	 * actual definition is 2 * 8-bit sample period.
1124*6c957ed7SJacopo Mondi 	 *
1125*6c957ed7SJacopo Mondi 	 * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
1126*6c957ed7SJacopo Mondi 	 */
1127*6c957ed7SJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
1128*6c957ed7SJacopo Mondi 	sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
1129*6c957ed7SJacopo Mondi 	pclk_period = 2000000000UL / sample_rate;
1130*6c957ed7SJacopo Mondi 
1131*6c957ed7SJacopo Mondi 	/* Program the clock tree registers. */
1132*6c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
1133*6c957ed7SJacopo Mondi 	if (ret)
1134*6c957ed7SJacopo Mondi 		return ret;
1135*6c957ed7SJacopo Mondi 
1136*6c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
1137*6c957ed7SJacopo Mondi 			     (sysdiv << 4) | mipi_div);
1138aa288248SMaxime Ripard 	if (ret)
1139aa288248SMaxime Ripard 		return ret;
1140aa288248SMaxime Ripard 
1141aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
1142aa288248SMaxime Ripard 	if (ret)
1143aa288248SMaxime Ripard 		return ret;
1144aa288248SMaxime Ripard 
1145*6c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
1146*6c957ed7SJacopo Mondi 			     root_div | prediv);
1147aa288248SMaxime Ripard 	if (ret)
1148aa288248SMaxime Ripard 		return ret;
1149aa288248SMaxime Ripard 
1150*6c957ed7SJacopo Mondi 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
1151*6c957ed7SJacopo Mondi 			     (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
1152*6c957ed7SJacopo Mondi 	if (ret)
1153*6c957ed7SJacopo Mondi 		return ret;
1154*6c957ed7SJacopo Mondi 
1155*6c957ed7SJacopo Mondi 	return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
1156*6c957ed7SJacopo Mondi }
1157*6c957ed7SJacopo Mondi 
1158*6c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
1159*6c957ed7SJacopo Mondi {
1160*6c957ed7SJacopo Mondi 	u32 rate;
1161*6c957ed7SJacopo Mondi 
1162*6c957ed7SJacopo Mondi 	rate = sensor->current_mode->vtot * sensor->current_mode->htot;
1163*6c957ed7SJacopo Mondi 	rate *= ov5640_framerates[sensor->current_fr];
1164*6c957ed7SJacopo Mondi 
1165*6c957ed7SJacopo Mondi 	return rate;
1166aa288248SMaxime Ripard }
1167aa288248SMaxime Ripard 
1168aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
1169aa288248SMaxime Ripard 				      unsigned long rate,
1170aa288248SMaxime Ripard 				      u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
1171aa288248SMaxime Ripard 				      u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
1172aa288248SMaxime Ripard {
1173aa288248SMaxime Ripard 	unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
1174aa288248SMaxime Ripard 				OV5640_PCLK_ROOT_DIV;
1175aa288248SMaxime Ripard 
1176aa288248SMaxime Ripard 	_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
1177aa288248SMaxime Ripard 				    sysdiv);
1178aa288248SMaxime Ripard 	*pll_rdiv = OV5640_PLL_ROOT_DIV;
1179aa288248SMaxime Ripard 	*bit_div = OV5640_BIT_DIV;
1180aa288248SMaxime Ripard 	*pclk_div = OV5640_PCLK_ROOT_DIV;
1181aa288248SMaxime Ripard 
1182aa288248SMaxime Ripard 	return _rate / *pll_rdiv / *bit_div / *pclk_div;
1183aa288248SMaxime Ripard }
1184aa288248SMaxime Ripard 
1185*6c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
1186aa288248SMaxime Ripard {
1187aa288248SMaxime Ripard 	u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
1188*6c957ed7SJacopo Mondi 	u32 rate;
1189aa288248SMaxime Ripard 	int ret;
1190aa288248SMaxime Ripard 
1191*6c957ed7SJacopo Mondi 	rate = ov5640_calc_pixel_rate(sensor);
1192*6c957ed7SJacopo Mondi 	rate *= ov5640_code_to_bpp(sensor->fmt.code);
1193*6c957ed7SJacopo Mondi 	rate /= sensor->ep.bus.parallel.bus_width;
1194*6c957ed7SJacopo Mondi 
1195aa288248SMaxime Ripard 	ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
1196aa288248SMaxime Ripard 			 &bit_div, &pclk_div);
1197aa288248SMaxime Ripard 
1198aa288248SMaxime Ripard 	if (bit_div == 2)
1199aa288248SMaxime Ripard 		bit_div = 8;
1200aa288248SMaxime Ripard 
1201aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
1202aa288248SMaxime Ripard 			     0x0f, bit_div);
1203aa288248SMaxime Ripard 	if (ret)
1204aa288248SMaxime Ripard 		return ret;
1205aa288248SMaxime Ripard 
1206aa288248SMaxime Ripard 	/*
1207aa288248SMaxime Ripard 	 * We need to set sysdiv according to the clock, and to clear
1208aa288248SMaxime Ripard 	 * the MIPI divider.
1209aa288248SMaxime Ripard 	 */
1210aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
1211aa288248SMaxime Ripard 			     0xff, sysdiv << 4);
1212aa288248SMaxime Ripard 	if (ret)
1213aa288248SMaxime Ripard 		return ret;
1214aa288248SMaxime Ripard 
1215aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
1216aa288248SMaxime Ripard 			     0xff, mult);
1217aa288248SMaxime Ripard 	if (ret)
1218aa288248SMaxime Ripard 		return ret;
1219aa288248SMaxime Ripard 
1220aa288248SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
1221aa288248SMaxime Ripard 			     0x1f, prediv | ((pll_rdiv - 1) << 4));
1222aa288248SMaxime Ripard 	if (ret)
1223aa288248SMaxime Ripard 		return ret;
1224aa288248SMaxime Ripard 
1225aa288248SMaxime Ripard 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
1226aa288248SMaxime Ripard 			      (ilog2(pclk_div) << 4));
1227aa288248SMaxime Ripard }
1228aa288248SMaxime Ripard 
12297cb013b1SChen-Yu Tsai /* set JPEG framing sizes */
12307cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
12317cb013b1SChen-Yu Tsai 				   const struct ov5640_mode_info *mode)
12327cb013b1SChen-Yu Tsai {
12337cb013b1SChen-Yu Tsai 	int ret;
12347cb013b1SChen-Yu Tsai 
12352b5c18f9SChen-Yu Tsai 	/*
12362b5c18f9SChen-Yu Tsai 	 * compression mode 3 timing
12372b5c18f9SChen-Yu Tsai 	 *
12382b5c18f9SChen-Yu Tsai 	 * Data is transmitted with programmable width (VFIFO_HSIZE).
12392b5c18f9SChen-Yu Tsai 	 * No padding done. Last line may have less data. Varying
12402b5c18f9SChen-Yu Tsai 	 * number of lines per frame, depending on amount of data.
12412b5c18f9SChen-Yu Tsai 	 */
12422b5c18f9SChen-Yu Tsai 	ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3);
12432b5c18f9SChen-Yu Tsai 	if (ret < 0)
12442b5c18f9SChen-Yu Tsai 		return ret;
12452b5c18f9SChen-Yu Tsai 
12467cb013b1SChen-Yu Tsai 	ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact);
12477cb013b1SChen-Yu Tsai 	if (ret < 0)
12487cb013b1SChen-Yu Tsai 		return ret;
12497cb013b1SChen-Yu Tsai 
12507cb013b1SChen-Yu Tsai 	return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact);
12517cb013b1SChen-Yu Tsai }
12527cb013b1SChen-Yu Tsai 
125319a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */
1254bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor,
1255bad1774eSJacopo Mondi 			      const struct ov5640_mode_info *mode)
1256bad1774eSJacopo Mondi {
1257bad1774eSJacopo Mondi 	int ret;
1258bad1774eSJacopo Mondi 
12597cb013b1SChen-Yu Tsai 	if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
12607cb013b1SChen-Yu Tsai 		ret = ov5640_set_jpeg_timings(sensor, mode);
12617cb013b1SChen-Yu Tsai 		if (ret < 0)
12627cb013b1SChen-Yu Tsai 			return ret;
12637cb013b1SChen-Yu Tsai 	}
12647cb013b1SChen-Yu Tsai 
1265bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
1266bad1774eSJacopo Mondi 	if (ret < 0)
1267bad1774eSJacopo Mondi 		return ret;
1268bad1774eSJacopo Mondi 
1269bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
1270bad1774eSJacopo Mondi 	if (ret < 0)
1271bad1774eSJacopo Mondi 		return ret;
1272bad1774eSJacopo Mondi 
1273bad1774eSJacopo Mondi 	ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
1274bad1774eSJacopo Mondi 	if (ret < 0)
1275bad1774eSJacopo Mondi 		return ret;
1276bad1774eSJacopo Mondi 
1277bad1774eSJacopo Mondi 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
1278bad1774eSJacopo Mondi }
1279bad1774eSJacopo Mondi 
128019a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor,
128119a81c14SSteve Longerbeam 			    const struct ov5640_mode_info *mode)
128219a81c14SSteve Longerbeam {
128319a81c14SSteve Longerbeam 	const struct reg_value *regs = mode->reg_data;
128419a81c14SSteve Longerbeam 	unsigned int i;
128519a81c14SSteve Longerbeam 	u32 delay_ms;
128619a81c14SSteve Longerbeam 	u16 reg_addr;
128719a81c14SSteve Longerbeam 	u8 mask, val;
128819a81c14SSteve Longerbeam 	int ret = 0;
128919a81c14SSteve Longerbeam 
129019a81c14SSteve Longerbeam 	for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
129119a81c14SSteve Longerbeam 		delay_ms = regs->delay_ms;
129219a81c14SSteve Longerbeam 		reg_addr = regs->reg_addr;
129319a81c14SSteve Longerbeam 		val = regs->val;
129419a81c14SSteve Longerbeam 		mask = regs->mask;
129519a81c14SSteve Longerbeam 
12963b987d70SLad Prabhakar 		/* remain in power down mode for DVP */
12973b987d70SLad Prabhakar 		if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
12983b987d70SLad Prabhakar 		    val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
12998e823f5cSJacopo Mondi 		    !ov5640_is_csi2(sensor))
13003b987d70SLad Prabhakar 			continue;
13013b987d70SLad Prabhakar 
130219a81c14SSteve Longerbeam 		if (mask)
130319a81c14SSteve Longerbeam 			ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
130419a81c14SSteve Longerbeam 		else
130519a81c14SSteve Longerbeam 			ret = ov5640_write_reg(sensor, reg_addr, val);
130619a81c14SSteve Longerbeam 		if (ret)
130719a81c14SSteve Longerbeam 			break;
130819a81c14SSteve Longerbeam 
130919a81c14SSteve Longerbeam 		if (delay_ms)
131019a81c14SSteve Longerbeam 			usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
131119a81c14SSteve Longerbeam 	}
131219a81c14SSteve Longerbeam 
1313bad1774eSJacopo Mondi 	return ov5640_set_timings(sensor, mode);
131419a81c14SSteve Longerbeam }
131519a81c14SSteve Longerbeam 
1316dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
1317dc29a1c1SHugues Fruchet {
1318dc29a1c1SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
1319dc29a1c1SHugues Fruchet 			      BIT(0), on ? 0 : BIT(0));
1320dc29a1c1SHugues Fruchet }
1321dc29a1c1SHugues Fruchet 
132219a81c14SSteve Longerbeam /* read exposure, in number of line periods */
132319a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor)
132419a81c14SSteve Longerbeam {
132519a81c14SSteve Longerbeam 	int exp, ret;
132619a81c14SSteve Longerbeam 	u8 temp;
132719a81c14SSteve Longerbeam 
132819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp);
132919a81c14SSteve Longerbeam 	if (ret)
133019a81c14SSteve Longerbeam 		return ret;
133119a81c14SSteve Longerbeam 	exp = ((int)temp & 0x0f) << 16;
133219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp);
133319a81c14SSteve Longerbeam 	if (ret)
133419a81c14SSteve Longerbeam 		return ret;
133519a81c14SSteve Longerbeam 	exp |= ((int)temp << 8);
133619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp);
133719a81c14SSteve Longerbeam 	if (ret)
133819a81c14SSteve Longerbeam 		return ret;
133919a81c14SSteve Longerbeam 	exp |= (int)temp;
134019a81c14SSteve Longerbeam 
134119a81c14SSteve Longerbeam 	return exp >> 4;
134219a81c14SSteve Longerbeam }
134319a81c14SSteve Longerbeam 
134419a81c14SSteve Longerbeam /* write exposure, given number of line periods */
134519a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure)
134619a81c14SSteve Longerbeam {
134719a81c14SSteve Longerbeam 	int ret;
134819a81c14SSteve Longerbeam 
134919a81c14SSteve Longerbeam 	exposure <<= 4;
135019a81c14SSteve Longerbeam 
135119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
135219a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_LO,
135319a81c14SSteve Longerbeam 			       exposure & 0xff);
135419a81c14SSteve Longerbeam 	if (ret)
135519a81c14SSteve Longerbeam 		return ret;
135619a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor,
135719a81c14SSteve Longerbeam 			       OV5640_REG_AEC_PK_EXPOSURE_MED,
135819a81c14SSteve Longerbeam 			       (exposure >> 8) & 0xff);
135919a81c14SSteve Longerbeam 	if (ret)
136019a81c14SSteve Longerbeam 		return ret;
136119a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor,
136219a81c14SSteve Longerbeam 				OV5640_REG_AEC_PK_EXPOSURE_HI,
136319a81c14SSteve Longerbeam 				(exposure >> 16) & 0x0f);
136419a81c14SSteve Longerbeam }
136519a81c14SSteve Longerbeam 
136619a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor)
136719a81c14SSteve Longerbeam {
136819a81c14SSteve Longerbeam 	u16 gain;
136919a81c14SSteve Longerbeam 	int ret;
137019a81c14SSteve Longerbeam 
137119a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain);
137219a81c14SSteve Longerbeam 	if (ret)
137319a81c14SSteve Longerbeam 		return ret;
137419a81c14SSteve Longerbeam 
137519a81c14SSteve Longerbeam 	return gain & 0x3ff;
137619a81c14SSteve Longerbeam }
137719a81c14SSteve Longerbeam 
13783cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain)
13793cca8ef5SHugues Fruchet {
13803cca8ef5SHugues Fruchet 	return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN,
13813cca8ef5SHugues Fruchet 				  (u16)gain & 0x3ff);
13823cca8ef5SHugues Fruchet }
13833cca8ef5SHugues Fruchet 
13843cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
13853cca8ef5SHugues Fruchet {
13863cca8ef5SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL,
13873cca8ef5SHugues Fruchet 			      BIT(1), on ? 0 : BIT(1));
13883cca8ef5SHugues Fruchet }
13893cca8ef5SHugues Fruchet 
1390f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
1391f22996dbSHugues Fruchet {
13923b987d70SLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
13933b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWUP :
13943b987d70SLad Prabhakar 				OV5640_REG_SYS_CTRL0_SW_PWDN);
1395f22996dbSHugues Fruchet }
1396f22996dbSHugues Fruchet 
1397f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
139819a81c14SSteve Longerbeam {
139919a81c14SSteve Longerbeam 	int ret;
140019a81c14SSteve Longerbeam 
1401aa4bb8b8SJacopo Mondi 	/*
1402aa4bb8b8SJacopo Mondi 	 * Enable/disable the MIPI interface
1403aa4bb8b8SJacopo Mondi 	 *
1404aa4bb8b8SJacopo Mondi 	 * 0x300e = on ? 0x45 : 0x40
1405aa4bb8b8SJacopo Mondi 	 *
1406aa4bb8b8SJacopo Mondi 	 * FIXME: the sensor manual (version 2.03) reports
1407aa4bb8b8SJacopo Mondi 	 * [7:5] = 000  : 1 data lane mode
1408aa4bb8b8SJacopo Mondi 	 * [7:5] = 001  : 2 data lanes mode
1409aa4bb8b8SJacopo Mondi 	 * But this settings do not work, while the following ones
1410aa4bb8b8SJacopo Mondi 	 * have been validated for 2 data lanes mode.
1411aa4bb8b8SJacopo Mondi 	 *
1412aa4bb8b8SJacopo Mondi 	 * [7:5] = 010	: 2 data lanes mode
1413aa4bb8b8SJacopo Mondi 	 * [4] = 0	: Power up MIPI HS Tx
1414aa4bb8b8SJacopo Mondi 	 * [3] = 0	: Power up MIPI LS Rx
1415aa4bb8b8SJacopo Mondi 	 * [2] = 1/0	: MIPI interface enable/disable
1416aa4bb8b8SJacopo Mondi 	 * [1:0] = 01/00: FIXME: 'debug'
1417aa4bb8b8SJacopo Mondi 	 */
1418aa4bb8b8SJacopo Mondi 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00,
1419aa4bb8b8SJacopo Mondi 			       on ? 0x45 : 0x40);
142019a81c14SSteve Longerbeam 	if (ret)
142119a81c14SSteve Longerbeam 		return ret;
142219a81c14SSteve Longerbeam 
142319a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01,
142419a81c14SSteve Longerbeam 				on ? 0x00 : 0x0f);
142519a81c14SSteve Longerbeam }
142619a81c14SSteve Longerbeam 
142719a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor)
142819a81c14SSteve Longerbeam {
142919a81c14SSteve Longerbeam 	 /* calculate sysclk */
143019a81c14SSteve Longerbeam 	u32 xvclk = sensor->xclk_freq / 10000;
143119a81c14SSteve Longerbeam 	u32 multiplier, prediv, VCO, sysdiv, pll_rdiv;
143219a81c14SSteve Longerbeam 	u32 sclk_rdiv_map[] = {1, 2, 4, 8};
143319a81c14SSteve Longerbeam 	u32 bit_div2x = 1, sclk_rdiv, sysclk;
143419a81c14SSteve Longerbeam 	u8 temp1, temp2;
143519a81c14SSteve Longerbeam 	int ret;
143619a81c14SSteve Longerbeam 
143719a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1);
143819a81c14SSteve Longerbeam 	if (ret)
143919a81c14SSteve Longerbeam 		return ret;
144019a81c14SSteve Longerbeam 	temp2 = temp1 & 0x0f;
144119a81c14SSteve Longerbeam 	if (temp2 == 8 || temp2 == 10)
144219a81c14SSteve Longerbeam 		bit_div2x = temp2 / 2;
144319a81c14SSteve Longerbeam 
144419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1);
144519a81c14SSteve Longerbeam 	if (ret)
144619a81c14SSteve Longerbeam 		return ret;
144719a81c14SSteve Longerbeam 	sysdiv = temp1 >> 4;
144819a81c14SSteve Longerbeam 	if (sysdiv == 0)
144919a81c14SSteve Longerbeam 		sysdiv = 16;
145019a81c14SSteve Longerbeam 
145119a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1);
145219a81c14SSteve Longerbeam 	if (ret)
145319a81c14SSteve Longerbeam 		return ret;
145419a81c14SSteve Longerbeam 	multiplier = temp1;
145519a81c14SSteve Longerbeam 
145619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1);
145719a81c14SSteve Longerbeam 	if (ret)
145819a81c14SSteve Longerbeam 		return ret;
145919a81c14SSteve Longerbeam 	prediv = temp1 & 0x0f;
146019a81c14SSteve Longerbeam 	pll_rdiv = ((temp1 >> 4) & 0x01) + 1;
146119a81c14SSteve Longerbeam 
146219a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1);
146319a81c14SSteve Longerbeam 	if (ret)
146419a81c14SSteve Longerbeam 		return ret;
146519a81c14SSteve Longerbeam 	temp2 = temp1 & 0x03;
146619a81c14SSteve Longerbeam 	sclk_rdiv = sclk_rdiv_map[temp2];
146719a81c14SSteve Longerbeam 
146819a81c14SSteve Longerbeam 	if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x)
146919a81c14SSteve Longerbeam 		return -EINVAL;
147019a81c14SSteve Longerbeam 
147119a81c14SSteve Longerbeam 	VCO = xvclk * multiplier / prediv;
147219a81c14SSteve Longerbeam 
147319a81c14SSteve Longerbeam 	sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv;
147419a81c14SSteve Longerbeam 
147519a81c14SSteve Longerbeam 	return sysclk;
147619a81c14SSteve Longerbeam }
147719a81c14SSteve Longerbeam 
147819a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor)
147919a81c14SSteve Longerbeam {
148019a81c14SSteve Longerbeam 	 /* read HTS from register settings */
148119a81c14SSteve Longerbeam 	u8 mode;
148219a81c14SSteve Longerbeam 	int ret;
148319a81c14SSteve Longerbeam 
148419a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode);
148519a81c14SSteve Longerbeam 	if (ret)
148619a81c14SSteve Longerbeam 		return ret;
148719a81c14SSteve Longerbeam 	mode &= 0xfb;
148819a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode);
148919a81c14SSteve Longerbeam }
149019a81c14SSteve Longerbeam 
149119a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor)
149219a81c14SSteve Longerbeam {
149319a81c14SSteve Longerbeam 	/* read HTS from register settings */
149419a81c14SSteve Longerbeam 	u16 hts;
149519a81c14SSteve Longerbeam 	int ret;
149619a81c14SSteve Longerbeam 
149719a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts);
149819a81c14SSteve Longerbeam 	if (ret)
149919a81c14SSteve Longerbeam 		return ret;
150019a81c14SSteve Longerbeam 	return hts;
150119a81c14SSteve Longerbeam }
150219a81c14SSteve Longerbeam 
150319a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor)
150419a81c14SSteve Longerbeam {
150519a81c14SSteve Longerbeam 	u16 vts;
150619a81c14SSteve Longerbeam 	int ret;
150719a81c14SSteve Longerbeam 
150819a81c14SSteve Longerbeam 	ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts);
150919a81c14SSteve Longerbeam 	if (ret)
151019a81c14SSteve Longerbeam 		return ret;
151119a81c14SSteve Longerbeam 	return vts;
151219a81c14SSteve Longerbeam }
151319a81c14SSteve Longerbeam 
151419a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts)
151519a81c14SSteve Longerbeam {
151619a81c14SSteve Longerbeam 	return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts);
151719a81c14SSteve Longerbeam }
151819a81c14SSteve Longerbeam 
151919a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor)
152019a81c14SSteve Longerbeam {
152119a81c14SSteve Longerbeam 	/* get banding filter value */
152219a81c14SSteve Longerbeam 	int ret, light_freq = 0;
152319a81c14SSteve Longerbeam 	u8 temp, temp1;
152419a81c14SSteve Longerbeam 
152519a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp);
152619a81c14SSteve Longerbeam 	if (ret)
152719a81c14SSteve Longerbeam 		return ret;
152819a81c14SSteve Longerbeam 
152919a81c14SSteve Longerbeam 	if (temp & 0x80) {
153019a81c14SSteve Longerbeam 		/* manual */
153119a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00,
153219a81c14SSteve Longerbeam 				      &temp1);
153319a81c14SSteve Longerbeam 		if (ret)
153419a81c14SSteve Longerbeam 			return ret;
153519a81c14SSteve Longerbeam 		if (temp1 & 0x04) {
153619a81c14SSteve Longerbeam 			/* 50Hz */
153719a81c14SSteve Longerbeam 			light_freq = 50;
153819a81c14SSteve Longerbeam 		} else {
153919a81c14SSteve Longerbeam 			/* 60Hz */
154019a81c14SSteve Longerbeam 			light_freq = 60;
154119a81c14SSteve Longerbeam 		}
154219a81c14SSteve Longerbeam 	} else {
154319a81c14SSteve Longerbeam 		/* auto */
154419a81c14SSteve Longerbeam 		ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C,
154519a81c14SSteve Longerbeam 				      &temp1);
154619a81c14SSteve Longerbeam 		if (ret)
154719a81c14SSteve Longerbeam 			return ret;
154819a81c14SSteve Longerbeam 
154919a81c14SSteve Longerbeam 		if (temp1 & 0x01) {
155019a81c14SSteve Longerbeam 			/* 50Hz */
155119a81c14SSteve Longerbeam 			light_freq = 50;
155219a81c14SSteve Longerbeam 		} else {
155319a81c14SSteve Longerbeam 			/* 60Hz */
155419a81c14SSteve Longerbeam 		}
155519a81c14SSteve Longerbeam 	}
155619a81c14SSteve Longerbeam 
155719a81c14SSteve Longerbeam 	return light_freq;
155819a81c14SSteve Longerbeam }
155919a81c14SSteve Longerbeam 
156019a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor)
156119a81c14SSteve Longerbeam {
156219a81c14SSteve Longerbeam 	u32 band_step60, max_band60, band_step50, max_band50, prev_vts;
156319a81c14SSteve Longerbeam 	int ret;
156419a81c14SSteve Longerbeam 
156519a81c14SSteve Longerbeam 	/* read preview PCLK */
156619a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
156719a81c14SSteve Longerbeam 	if (ret < 0)
156819a81c14SSteve Longerbeam 		return ret;
156919a81c14SSteve Longerbeam 	if (ret == 0)
157019a81c14SSteve Longerbeam 		return -EINVAL;
157119a81c14SSteve Longerbeam 	sensor->prev_sysclk = ret;
157219a81c14SSteve Longerbeam 	/* read preview HTS */
157319a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
157419a81c14SSteve Longerbeam 	if (ret < 0)
157519a81c14SSteve Longerbeam 		return ret;
157619a81c14SSteve Longerbeam 	if (ret == 0)
157719a81c14SSteve Longerbeam 		return -EINVAL;
157819a81c14SSteve Longerbeam 	sensor->prev_hts = ret;
157919a81c14SSteve Longerbeam 
158019a81c14SSteve Longerbeam 	/* read preview VTS */
158119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
158219a81c14SSteve Longerbeam 	if (ret < 0)
158319a81c14SSteve Longerbeam 		return ret;
158419a81c14SSteve Longerbeam 	prev_vts = ret;
158519a81c14SSteve Longerbeam 
158619a81c14SSteve Longerbeam 	/* calculate banding filter */
158719a81c14SSteve Longerbeam 	/* 60Hz */
158819a81c14SSteve Longerbeam 	band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120;
158919a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60);
159019a81c14SSteve Longerbeam 	if (ret)
159119a81c14SSteve Longerbeam 		return ret;
159219a81c14SSteve Longerbeam 	if (!band_step60)
159319a81c14SSteve Longerbeam 		return -EINVAL;
159419a81c14SSteve Longerbeam 	max_band60 = (int)((prev_vts - 4) / band_step60);
159519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60);
159619a81c14SSteve Longerbeam 	if (ret)
159719a81c14SSteve Longerbeam 		return ret;
159819a81c14SSteve Longerbeam 
159919a81c14SSteve Longerbeam 	/* 50Hz */
160019a81c14SSteve Longerbeam 	band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts;
160119a81c14SSteve Longerbeam 	ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50);
160219a81c14SSteve Longerbeam 	if (ret)
160319a81c14SSteve Longerbeam 		return ret;
160419a81c14SSteve Longerbeam 	if (!band_step50)
160519a81c14SSteve Longerbeam 		return -EINVAL;
160619a81c14SSteve Longerbeam 	max_band50 = (int)((prev_vts - 4) / band_step50);
160719a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50);
160819a81c14SSteve Longerbeam }
160919a81c14SSteve Longerbeam 
161019a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target)
161119a81c14SSteve Longerbeam {
161219a81c14SSteve Longerbeam 	/* stable in high */
161319a81c14SSteve Longerbeam 	u32 fast_high, fast_low;
161419a81c14SSteve Longerbeam 	int ret;
161519a81c14SSteve Longerbeam 
161619a81c14SSteve Longerbeam 	sensor->ae_low = target * 23 / 25;	/* 0.92 */
161719a81c14SSteve Longerbeam 	sensor->ae_high = target * 27 / 25;	/* 1.08 */
161819a81c14SSteve Longerbeam 
161919a81c14SSteve Longerbeam 	fast_high = sensor->ae_high << 1;
162019a81c14SSteve Longerbeam 	if (fast_high > 255)
162119a81c14SSteve Longerbeam 		fast_high = 255;
162219a81c14SSteve Longerbeam 
162319a81c14SSteve Longerbeam 	fast_low = sensor->ae_low >> 1;
162419a81c14SSteve Longerbeam 
162519a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high);
162619a81c14SSteve Longerbeam 	if (ret)
162719a81c14SSteve Longerbeam 		return ret;
162819a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low);
162919a81c14SSteve Longerbeam 	if (ret)
163019a81c14SSteve Longerbeam 		return ret;
163119a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high);
163219a81c14SSteve Longerbeam 	if (ret)
163319a81c14SSteve Longerbeam 		return ret;
163419a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low);
163519a81c14SSteve Longerbeam 	if (ret)
163619a81c14SSteve Longerbeam 		return ret;
163719a81c14SSteve Longerbeam 	ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high);
163819a81c14SSteve Longerbeam 	if (ret)
163919a81c14SSteve Longerbeam 		return ret;
164019a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low);
164119a81c14SSteve Longerbeam }
164219a81c14SSteve Longerbeam 
1643c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor)
164419a81c14SSteve Longerbeam {
164519a81c14SSteve Longerbeam 	u8 temp;
164619a81c14SSteve Longerbeam 	int ret;
164719a81c14SSteve Longerbeam 
164819a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp);
164919a81c14SSteve Longerbeam 	if (ret)
165019a81c14SSteve Longerbeam 		return ret;
1651c2c3f42dSHugues Fruchet 
1652c2c3f42dSHugues Fruchet 	return temp & BIT(0);
165319a81c14SSteve Longerbeam }
165419a81c14SSteve Longerbeam 
1655ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable)
1656ce85705aSHugues Fruchet {
1657ce85705aSHugues Fruchet 	int ret;
1658ce85705aSHugues Fruchet 
1659ce85705aSHugues Fruchet 	/*
1660ce85705aSHugues Fruchet 	 * TIMING TC REG21:
1661ce85705aSHugues Fruchet 	 * - [0]:	Horizontal binning enable
1662ce85705aSHugues Fruchet 	 */
1663ce85705aSHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
1664ce85705aSHugues Fruchet 			     BIT(0), enable ? BIT(0) : 0);
1665ce85705aSHugues Fruchet 	if (ret)
1666ce85705aSHugues Fruchet 		return ret;
1667ce85705aSHugues Fruchet 	/*
1668ce85705aSHugues Fruchet 	 * TIMING TC REG20:
1669ce85705aSHugues Fruchet 	 * - [0]:	Undocumented, but hardcoded init sequences
1670ce85705aSHugues Fruchet 	 *		are always setting REG21/REG20 bit 0 to same value...
1671ce85705aSHugues Fruchet 	 */
1672ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
1673ce85705aSHugues Fruchet 			      BIT(0), enable ? BIT(0) : 0);
1674ce85705aSHugues Fruchet }
1675ce85705aSHugues Fruchet 
167619a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
167719a81c14SSteve Longerbeam {
16788670d70aSHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
167919a81c14SSteve Longerbeam 	u8 temp, channel = virtual_channel;
168019a81c14SSteve Longerbeam 	int ret;
168119a81c14SSteve Longerbeam 
16828670d70aSHugues Fruchet 	if (channel > 3) {
16838670d70aSHugues Fruchet 		dev_err(&client->dev,
16848670d70aSHugues Fruchet 			"%s: wrong virtual_channel parameter, expected (0..3), got %d\n",
16858670d70aSHugues Fruchet 			__func__, channel);
168619a81c14SSteve Longerbeam 		return -EINVAL;
16878670d70aSHugues Fruchet 	}
168819a81c14SSteve Longerbeam 
168919a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp);
169019a81c14SSteve Longerbeam 	if (ret)
169119a81c14SSteve Longerbeam 		return ret;
169219a81c14SSteve Longerbeam 	temp &= ~(3 << 6);
169319a81c14SSteve Longerbeam 	temp |= (channel << 6);
169419a81c14SSteve Longerbeam 	return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
169519a81c14SSteve Longerbeam }
169619a81c14SSteve Longerbeam 
169719a81c14SSteve Longerbeam static const struct ov5640_mode_info *
169819a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
169919a81c14SSteve Longerbeam 		 int width, int height, bool nearest)
170019a81c14SSteve Longerbeam {
17013c4a7372SHugues Fruchet 	const struct ov5640_mode_info *mode;
170219a81c14SSteve Longerbeam 
1703086c25f8SMaxime Ripard 	mode = v4l2_find_nearest_size(ov5640_mode_data,
1704086c25f8SMaxime Ripard 				      ARRAY_SIZE(ov5640_mode_data),
17053c4a7372SHugues Fruchet 				      hact, vact,
17063c4a7372SHugues Fruchet 				      width, height);
170719a81c14SSteve Longerbeam 
17083c4a7372SHugues Fruchet 	if (!mode ||
17093c4a7372SHugues Fruchet 	    (!nearest && (mode->hact != width || mode->vact != height)))
17103c4a7372SHugues Fruchet 		return NULL;
171119a81c14SSteve Longerbeam 
17125554c80eSAdam Ford 	/* Check to see if the current mode exceeds the max frame rate */
17135554c80eSAdam Ford 	if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
1714981e4454SBenoit Parrot 		return NULL;
1715981e4454SBenoit Parrot 
171619a81c14SSteve Longerbeam 	return mode;
171719a81c14SSteve Longerbeam }
171819a81c14SSteve Longerbeam 
171919a81c14SSteve Longerbeam /*
172019a81c14SSteve Longerbeam  * sensor changes between scaling and subsampling, go through
172119a81c14SSteve Longerbeam  * exposure calculation
172219a81c14SSteve Longerbeam  */
172341d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
172441d8d7f5SHugues Fruchet 					 const struct ov5640_mode_info *mode)
172519a81c14SSteve Longerbeam {
172619a81c14SSteve Longerbeam 	u32 prev_shutter, prev_gain16;
172719a81c14SSteve Longerbeam 	u32 cap_shutter, cap_gain16;
172819a81c14SSteve Longerbeam 	u32 cap_sysclk, cap_hts, cap_vts;
172919a81c14SSteve Longerbeam 	u32 light_freq, cap_bandfilt, cap_maxband;
173019a81c14SSteve Longerbeam 	u32 cap_gain16_shutter;
173119a81c14SSteve Longerbeam 	u8 average;
173219a81c14SSteve Longerbeam 	int ret;
173319a81c14SSteve Longerbeam 
173441d8d7f5SHugues Fruchet 	if (!mode->reg_data)
173519a81c14SSteve Longerbeam 		return -EINVAL;
173619a81c14SSteve Longerbeam 
173719a81c14SSteve Longerbeam 	/* read preview shutter */
173819a81c14SSteve Longerbeam 	ret = ov5640_get_exposure(sensor);
173919a81c14SSteve Longerbeam 	if (ret < 0)
174019a81c14SSteve Longerbeam 		return ret;
174119a81c14SSteve Longerbeam 	prev_shutter = ret;
1742c2c3f42dSHugues Fruchet 	ret = ov5640_get_binning(sensor);
174319a81c14SSteve Longerbeam 	if (ret < 0)
174419a81c14SSteve Longerbeam 		return ret;
174519a81c14SSteve Longerbeam 	if (ret && mode->id != OV5640_MODE_720P_1280_720 &&
174619a81c14SSteve Longerbeam 	    mode->id != OV5640_MODE_1080P_1920_1080)
174719a81c14SSteve Longerbeam 		prev_shutter *= 2;
174819a81c14SSteve Longerbeam 
174919a81c14SSteve Longerbeam 	/* read preview gain */
175019a81c14SSteve Longerbeam 	ret = ov5640_get_gain(sensor);
175119a81c14SSteve Longerbeam 	if (ret < 0)
175219a81c14SSteve Longerbeam 		return ret;
175319a81c14SSteve Longerbeam 	prev_gain16 = ret;
175419a81c14SSteve Longerbeam 
175519a81c14SSteve Longerbeam 	/* get average */
175619a81c14SSteve Longerbeam 	ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average);
175719a81c14SSteve Longerbeam 	if (ret)
175819a81c14SSteve Longerbeam 		return ret;
175919a81c14SSteve Longerbeam 
176019a81c14SSteve Longerbeam 	/* turn off night mode for capture */
176119a81c14SSteve Longerbeam 	ret = ov5640_set_night_mode(sensor);
176219a81c14SSteve Longerbeam 	if (ret < 0)
176319a81c14SSteve Longerbeam 		return ret;
176419a81c14SSteve Longerbeam 
176519a81c14SSteve Longerbeam 	/* Write capture setting */
176619a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, mode);
176719a81c14SSteve Longerbeam 	if (ret < 0)
176819a81c14SSteve Longerbeam 		return ret;
176919a81c14SSteve Longerbeam 
177019a81c14SSteve Longerbeam 	/* read capture VTS */
177119a81c14SSteve Longerbeam 	ret = ov5640_get_vts(sensor);
177219a81c14SSteve Longerbeam 	if (ret < 0)
177319a81c14SSteve Longerbeam 		return ret;
177419a81c14SSteve Longerbeam 	cap_vts = ret;
177519a81c14SSteve Longerbeam 	ret = ov5640_get_hts(sensor);
177619a81c14SSteve Longerbeam 	if (ret < 0)
177719a81c14SSteve Longerbeam 		return ret;
177819a81c14SSteve Longerbeam 	if (ret == 0)
177919a81c14SSteve Longerbeam 		return -EINVAL;
178019a81c14SSteve Longerbeam 	cap_hts = ret;
178119a81c14SSteve Longerbeam 
178219a81c14SSteve Longerbeam 	ret = ov5640_get_sysclk(sensor);
178319a81c14SSteve Longerbeam 	if (ret < 0)
178419a81c14SSteve Longerbeam 		return ret;
178519a81c14SSteve Longerbeam 	if (ret == 0)
178619a81c14SSteve Longerbeam 		return -EINVAL;
178719a81c14SSteve Longerbeam 	cap_sysclk = ret;
178819a81c14SSteve Longerbeam 
178919a81c14SSteve Longerbeam 	/* calculate capture banding filter */
179019a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
179119a81c14SSteve Longerbeam 	if (ret < 0)
179219a81c14SSteve Longerbeam 		return ret;
179319a81c14SSteve Longerbeam 	light_freq = ret;
179419a81c14SSteve Longerbeam 
179519a81c14SSteve Longerbeam 	if (light_freq == 60) {
179619a81c14SSteve Longerbeam 		/* 60Hz */
179719a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120;
179819a81c14SSteve Longerbeam 	} else {
179919a81c14SSteve Longerbeam 		/* 50Hz */
180019a81c14SSteve Longerbeam 		cap_bandfilt = cap_sysclk * 100 / cap_hts;
180119a81c14SSteve Longerbeam 	}
180219a81c14SSteve Longerbeam 
180319a81c14SSteve Longerbeam 	if (!sensor->prev_sysclk) {
180419a81c14SSteve Longerbeam 		ret = ov5640_get_sysclk(sensor);
180519a81c14SSteve Longerbeam 		if (ret < 0)
180619a81c14SSteve Longerbeam 			return ret;
180719a81c14SSteve Longerbeam 		if (ret == 0)
180819a81c14SSteve Longerbeam 			return -EINVAL;
180919a81c14SSteve Longerbeam 		sensor->prev_sysclk = ret;
181019a81c14SSteve Longerbeam 	}
181119a81c14SSteve Longerbeam 
181219a81c14SSteve Longerbeam 	if (!cap_bandfilt)
181319a81c14SSteve Longerbeam 		return -EINVAL;
181419a81c14SSteve Longerbeam 
181519a81c14SSteve Longerbeam 	cap_maxband = (int)((cap_vts - 4) / cap_bandfilt);
181619a81c14SSteve Longerbeam 
181719a81c14SSteve Longerbeam 	/* calculate capture shutter/gain16 */
181819a81c14SSteve Longerbeam 	if (average > sensor->ae_low && average < sensor->ae_high) {
181919a81c14SSteve Longerbeam 		/* in stable range */
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 			sensor->ae_target / average;
182519a81c14SSteve Longerbeam 	} else {
182619a81c14SSteve Longerbeam 		cap_gain16_shutter =
182719a81c14SSteve Longerbeam 			prev_gain16 * prev_shutter *
182819a81c14SSteve Longerbeam 			cap_sysclk / sensor->prev_sysclk *
182919a81c14SSteve Longerbeam 			sensor->prev_hts / cap_hts;
183019a81c14SSteve Longerbeam 	}
183119a81c14SSteve Longerbeam 
183219a81c14SSteve Longerbeam 	/* gain to shutter */
183319a81c14SSteve Longerbeam 	if (cap_gain16_shutter < (cap_bandfilt * 16)) {
183419a81c14SSteve Longerbeam 		/* shutter < 1/100 */
183519a81c14SSteve Longerbeam 		cap_shutter = cap_gain16_shutter / 16;
183619a81c14SSteve Longerbeam 		if (cap_shutter < 1)
183719a81c14SSteve Longerbeam 			cap_shutter = 1;
183819a81c14SSteve Longerbeam 
183919a81c14SSteve Longerbeam 		cap_gain16 = cap_gain16_shutter / cap_shutter;
184019a81c14SSteve Longerbeam 		if (cap_gain16 < 16)
184119a81c14SSteve Longerbeam 			cap_gain16 = 16;
184219a81c14SSteve Longerbeam 	} else {
184319a81c14SSteve Longerbeam 		if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) {
184419a81c14SSteve Longerbeam 			/* exposure reach max */
184519a81c14SSteve Longerbeam 			cap_shutter = cap_bandfilt * cap_maxband;
184619a81c14SSteve Longerbeam 			if (!cap_shutter)
184719a81c14SSteve Longerbeam 				return -EINVAL;
184819a81c14SSteve Longerbeam 
184919a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
185019a81c14SSteve Longerbeam 		} else {
185119a81c14SSteve Longerbeam 			/* 1/100 < (cap_shutter = n/100) =< max */
185219a81c14SSteve Longerbeam 			cap_shutter =
185319a81c14SSteve Longerbeam 				((int)(cap_gain16_shutter / 16 / cap_bandfilt))
185419a81c14SSteve Longerbeam 				* cap_bandfilt;
185519a81c14SSteve Longerbeam 			if (!cap_shutter)
185619a81c14SSteve Longerbeam 				return -EINVAL;
185719a81c14SSteve Longerbeam 
185819a81c14SSteve Longerbeam 			cap_gain16 = cap_gain16_shutter / cap_shutter;
185919a81c14SSteve Longerbeam 		}
186019a81c14SSteve Longerbeam 	}
186119a81c14SSteve Longerbeam 
186219a81c14SSteve Longerbeam 	/* set capture gain */
18633cca8ef5SHugues Fruchet 	ret = ov5640_set_gain(sensor, cap_gain16);
186419a81c14SSteve Longerbeam 	if (ret)
186519a81c14SSteve Longerbeam 		return ret;
186619a81c14SSteve Longerbeam 
186719a81c14SSteve Longerbeam 	/* write capture shutter */
186819a81c14SSteve Longerbeam 	if (cap_shutter > (cap_vts - 4)) {
186919a81c14SSteve Longerbeam 		cap_vts = cap_shutter + 4;
187019a81c14SSteve Longerbeam 		ret = ov5640_set_vts(sensor, cap_vts);
187119a81c14SSteve Longerbeam 		if (ret < 0)
187219a81c14SSteve Longerbeam 			return ret;
187319a81c14SSteve Longerbeam 	}
187419a81c14SSteve Longerbeam 
187519a81c14SSteve Longerbeam 	/* set exposure */
18763cca8ef5SHugues Fruchet 	return ov5640_set_exposure(sensor, cap_shutter);
187719a81c14SSteve Longerbeam }
187819a81c14SSteve Longerbeam 
187919a81c14SSteve Longerbeam /*
188019a81c14SSteve Longerbeam  * if sensor changes inside scaling or subsampling
188119a81c14SSteve Longerbeam  * change mode directly
188219a81c14SSteve Longerbeam  */
188319a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
18843cca8ef5SHugues Fruchet 				  const struct ov5640_mode_info *mode)
188519a81c14SSteve Longerbeam {
188641d8d7f5SHugues Fruchet 	if (!mode->reg_data)
188719a81c14SSteve Longerbeam 		return -EINVAL;
188819a81c14SSteve Longerbeam 
188919a81c14SSteve Longerbeam 	/* Write capture setting */
18903cca8ef5SHugues Fruchet 	return ov5640_load_regs(sensor, mode);
189119a81c14SSteve Longerbeam }
189219a81c14SSteve Longerbeam 
1893985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor)
189419a81c14SSteve Longerbeam {
189519a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode = sensor->current_mode;
1896985cdcb0SHugues Fruchet 	const struct ov5640_mode_info *orig_mode = sensor->last_mode;
189719a81c14SSteve Longerbeam 	enum ov5640_downsize_mode dn_mode, orig_dn_mode;
18983cca8ef5SHugues Fruchet 	bool auto_gain = sensor->ctrls.auto_gain->val == 1;
1899dc29a1c1SHugues Fruchet 	bool auto_exp =  sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
190019a81c14SSteve Longerbeam 	int ret;
190119a81c14SSteve Longerbeam 
190219a81c14SSteve Longerbeam 	dn_mode = mode->dn_mode;
190319a81c14SSteve Longerbeam 	orig_dn_mode = orig_mode->dn_mode;
190419a81c14SSteve Longerbeam 
190519a81c14SSteve Longerbeam 	/* auto gain and exposure must be turned off when changing modes */
19063cca8ef5SHugues Fruchet 	if (auto_gain) {
19073cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, false);
190819a81c14SSteve Longerbeam 		if (ret)
190919a81c14SSteve Longerbeam 			return ret;
19103cca8ef5SHugues Fruchet 	}
1911bf4a4b51SMaxime Ripard 
19123cca8ef5SHugues Fruchet 	if (auto_exp) {
1913dc29a1c1SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, false);
191419a81c14SSteve Longerbeam 		if (ret)
19153cca8ef5SHugues Fruchet 			goto restore_auto_gain;
19163cca8ef5SHugues Fruchet 	}
191719a81c14SSteve Longerbeam 
1918*6c957ed7SJacopo Mondi 	if (ov5640_is_csi2(sensor))
1919*6c957ed7SJacopo Mondi 		ret = ov5640_set_mipi_pclk(sensor);
1920*6c957ed7SJacopo Mondi 	else
1921*6c957ed7SJacopo Mondi 		ret = ov5640_set_dvp_pclk(sensor);
1922aa288248SMaxime Ripard 	if (ret < 0)
1923aa288248SMaxime Ripard 		return 0;
1924aa288248SMaxime Ripard 
192519a81c14SSteve Longerbeam 	if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
192619a81c14SSteve Longerbeam 	    (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
192719a81c14SSteve Longerbeam 		/*
192819a81c14SSteve Longerbeam 		 * change between subsampling and scaling
19293cca8ef5SHugues Fruchet 		 * go through exposure calculation
193019a81c14SSteve Longerbeam 		 */
193119a81c14SSteve Longerbeam 		ret = ov5640_set_mode_exposure_calc(sensor, mode);
193219a81c14SSteve Longerbeam 	} else {
193319a81c14SSteve Longerbeam 		/*
193419a81c14SSteve Longerbeam 		 * change inside subsampling or scaling
193519a81c14SSteve Longerbeam 		 * download firmware directly
193619a81c14SSteve Longerbeam 		 */
19373cca8ef5SHugues Fruchet 		ret = ov5640_set_mode_direct(sensor, mode);
193819a81c14SSteve Longerbeam 	}
193919a81c14SSteve Longerbeam 	if (ret < 0)
19403cca8ef5SHugues Fruchet 		goto restore_auto_exp_gain;
19413cca8ef5SHugues Fruchet 
19423cca8ef5SHugues Fruchet 	/* restore auto gain and exposure */
19433cca8ef5SHugues Fruchet 	if (auto_gain)
19443cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
19453cca8ef5SHugues Fruchet 	if (auto_exp)
19463cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
194719a81c14SSteve Longerbeam 
1948ce85705aSHugues Fruchet 	ret = ov5640_set_binning(sensor, dn_mode != SCALING);
1949ce85705aSHugues Fruchet 	if (ret < 0)
1950ce85705aSHugues Fruchet 		return ret;
195119a81c14SSteve Longerbeam 	ret = ov5640_set_ae_target(sensor, sensor->ae_target);
195219a81c14SSteve Longerbeam 	if (ret < 0)
195319a81c14SSteve Longerbeam 		return ret;
195419a81c14SSteve Longerbeam 	ret = ov5640_get_light_freq(sensor);
195519a81c14SSteve Longerbeam 	if (ret < 0)
195619a81c14SSteve Longerbeam 		return ret;
195719a81c14SSteve Longerbeam 	ret = ov5640_set_bandingfilter(sensor);
195819a81c14SSteve Longerbeam 	if (ret < 0)
195919a81c14SSteve Longerbeam 		return ret;
196019a81c14SSteve Longerbeam 	ret = ov5640_set_virtual_channel(sensor);
196119a81c14SSteve Longerbeam 	if (ret < 0)
196219a81c14SSteve Longerbeam 		return ret;
196319a81c14SSteve Longerbeam 
196419a81c14SSteve Longerbeam 	sensor->pending_mode_change = false;
1965985cdcb0SHugues Fruchet 	sensor->last_mode = mode;
196619a81c14SSteve Longerbeam 
196719a81c14SSteve Longerbeam 	return 0;
19683cca8ef5SHugues Fruchet 
19693cca8ef5SHugues Fruchet restore_auto_exp_gain:
19703cca8ef5SHugues Fruchet 	if (auto_exp)
19713cca8ef5SHugues Fruchet 		ov5640_set_autoexposure(sensor, true);
19723cca8ef5SHugues Fruchet restore_auto_gain:
19733cca8ef5SHugues Fruchet 	if (auto_gain)
19743cca8ef5SHugues Fruchet 		ov5640_set_autogain(sensor, true);
19753cca8ef5SHugues Fruchet 
19763cca8ef5SHugues Fruchet 	return ret;
197719a81c14SSteve Longerbeam }
197819a81c14SSteve Longerbeam 
197919ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor,
198019ad26f9SAkinobu Mita 			       struct v4l2_mbus_framefmt *format);
198119ad26f9SAkinobu Mita 
198219a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */
198319a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor)
198419a81c14SSteve Longerbeam {
198519a81c14SSteve Longerbeam 	int ret;
198619a81c14SSteve Longerbeam 
198719a81c14SSteve Longerbeam 	/* first load the initial register values */
198819a81c14SSteve Longerbeam 	ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
198919a81c14SSteve Longerbeam 	if (ret < 0)
199019a81c14SSteve Longerbeam 		return ret;
1991985cdcb0SHugues Fruchet 	sensor->last_mode = &ov5640_mode_init_data;
199219a81c14SSteve Longerbeam 
19938f57c2f8SMaxime Ripard 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
19947851fe7aSMaxime Ripard 			     (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
19957851fe7aSMaxime Ripard 			     ilog2(OV5640_SCLK_ROOT_DIV));
19968f57c2f8SMaxime Ripard 	if (ret)
19978f57c2f8SMaxime Ripard 		return ret;
19988f57c2f8SMaxime Ripard 
199919a81c14SSteve Longerbeam 	/* now restore the last capture mode */
2000985cdcb0SHugues Fruchet 	ret = ov5640_set_mode(sensor);
200119ad26f9SAkinobu Mita 	if (ret < 0)
200219ad26f9SAkinobu Mita 		return ret;
200319ad26f9SAkinobu Mita 
200419ad26f9SAkinobu Mita 	return ov5640_set_framefmt(sensor, &sensor->fmt);
200519a81c14SSteve Longerbeam }
200619a81c14SSteve Longerbeam 
200719a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable)
200819a81c14SSteve Longerbeam {
20091fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1);
201019a81c14SSteve Longerbeam }
201119a81c14SSteve Longerbeam 
201219a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor)
201319a81c14SSteve Longerbeam {
201419a81c14SSteve Longerbeam 	if (!sensor->reset_gpio)
201519a81c14SSteve Longerbeam 		return;
201619a81c14SSteve Longerbeam 
20171fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
201819a81c14SSteve Longerbeam 
201919a81c14SSteve Longerbeam 	/* camera power cycle */
202019a81c14SSteve Longerbeam 	ov5640_power(sensor, false);
202119a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
202219a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
202319a81c14SSteve Longerbeam 	usleep_range(5000, 10000);
202419a81c14SSteve Longerbeam 
20251fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 1);
202619a81c14SSteve Longerbeam 	usleep_range(1000, 2000);
202719a81c14SSteve Longerbeam 
20281fddc5daSHugues Fruchet 	gpiod_set_value_cansleep(sensor->reset_gpio, 0);
20291d4c41f3SLoic Poulain 	usleep_range(20000, 25000);
203019a81c14SSteve Longerbeam }
203119a81c14SSteve Longerbeam 
20320f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor)
203319a81c14SSteve Longerbeam {
20340f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
20350f7acb52SHugues Fruchet 	int ret;
203619a81c14SSteve Longerbeam 
20370f7acb52SHugues Fruchet 	ret = clk_prepare_enable(sensor->xclk);
20380f7acb52SHugues Fruchet 	if (ret) {
20390f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable clock\n",
20400f7acb52SHugues Fruchet 			__func__);
20410f7acb52SHugues Fruchet 		return ret;
20420f7acb52SHugues Fruchet 	}
204319a81c14SSteve Longerbeam 
204419a81c14SSteve Longerbeam 	ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES,
204519a81c14SSteve Longerbeam 				    sensor->supplies);
20460f7acb52SHugues Fruchet 	if (ret) {
20470f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to enable regulators\n",
20480f7acb52SHugues Fruchet 			__func__);
204919a81c14SSteve Longerbeam 		goto xclk_off;
20500f7acb52SHugues Fruchet 	}
205119a81c14SSteve Longerbeam 
205219a81c14SSteve Longerbeam 	ov5640_reset(sensor);
205319a81c14SSteve Longerbeam 	ov5640_power(sensor, true);
205419a81c14SSteve Longerbeam 
205519a81c14SSteve Longerbeam 	ret = ov5640_init_slave_id(sensor);
205619a81c14SSteve Longerbeam 	if (ret)
205719a81c14SSteve Longerbeam 		goto power_off;
205819a81c14SSteve Longerbeam 
20590f7acb52SHugues Fruchet 	return 0;
20600f7acb52SHugues Fruchet 
20610f7acb52SHugues Fruchet power_off:
20620f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
20630f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
20640f7acb52SHugues Fruchet xclk_off:
20650f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
20660f7acb52SHugues Fruchet 	return ret;
20670f7acb52SHugues Fruchet }
20680f7acb52SHugues Fruchet 
20690f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor)
20700f7acb52SHugues Fruchet {
20710f7acb52SHugues Fruchet 	ov5640_power(sensor, false);
20720f7acb52SHugues Fruchet 	regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
20730f7acb52SHugues Fruchet 	clk_disable_unprepare(sensor->xclk);
20740f7acb52SHugues Fruchet }
20750f7acb52SHugues Fruchet 
2076b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
2077b1751ae6SLad Prabhakar {
2078b1751ae6SLad Prabhakar 	int ret;
2079b1751ae6SLad Prabhakar 
2080b1751ae6SLad Prabhakar 	if (!on) {
2081b1751ae6SLad Prabhakar 		/* Reset MIPI bus settings to their default values. */
2082b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2083b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
2084b1751ae6SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
2085b1751ae6SLad Prabhakar 		return 0;
2086b1751ae6SLad Prabhakar 	}
2087b1751ae6SLad Prabhakar 
2088b1751ae6SLad Prabhakar 	/*
2089b1751ae6SLad Prabhakar 	 * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
2090b1751ae6SLad Prabhakar 	 *
2091b1751ae6SLad Prabhakar 	 * 0x300e = 0x40
2092b1751ae6SLad Prabhakar 	 * [7:5] = 010	: 2 data lanes mode (see FIXME note in
2093b1751ae6SLad Prabhakar 	 *		  "ov5640_set_stream_mipi()")
2094b1751ae6SLad Prabhakar 	 * [4] = 0	: Power up MIPI HS Tx
2095b1751ae6SLad Prabhakar 	 * [3] = 0	: Power up MIPI LS Rx
2096b1751ae6SLad Prabhakar 	 * [2] = 0	: MIPI interface disabled
2097b1751ae6SLad Prabhakar 	 */
2098b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
2099b1751ae6SLad Prabhakar 	if (ret)
2100b1751ae6SLad Prabhakar 		return ret;
2101b1751ae6SLad Prabhakar 
2102b1751ae6SLad Prabhakar 	/*
2103b1751ae6SLad Prabhakar 	 * Gate clock and set LP11 in 'no packets mode' (idle)
2104b1751ae6SLad Prabhakar 	 *
2105b1751ae6SLad Prabhakar 	 * 0x4800 = 0x24
2106b1751ae6SLad Prabhakar 	 * [5] = 1	: Gate clock when 'no packets'
2107b1751ae6SLad Prabhakar 	 * [2] = 1	: MIPI bus in LP11 when 'no packets'
2108b1751ae6SLad Prabhakar 	 */
2109b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
2110b1751ae6SLad Prabhakar 	if (ret)
2111b1751ae6SLad Prabhakar 		return ret;
2112b1751ae6SLad Prabhakar 
2113b1751ae6SLad Prabhakar 	/*
2114b1751ae6SLad Prabhakar 	 * Set data lanes and clock in LP11 when 'sleeping'
2115b1751ae6SLad Prabhakar 	 *
2116b1751ae6SLad Prabhakar 	 * 0x3019 = 0x70
2117b1751ae6SLad Prabhakar 	 * [6] = 1	: MIPI data lane 2 in LP11 when 'sleeping'
2118b1751ae6SLad Prabhakar 	 * [5] = 1	: MIPI data lane 1 in LP11 when 'sleeping'
2119b1751ae6SLad Prabhakar 	 * [4] = 1	: MIPI clock lane in LP11 when 'sleeping'
2120b1751ae6SLad Prabhakar 	 */
2121b1751ae6SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
2122b1751ae6SLad Prabhakar 	if (ret)
2123b1751ae6SLad Prabhakar 		return ret;
2124b1751ae6SLad Prabhakar 
2125b1751ae6SLad Prabhakar 	/* Give lanes some time to coax into LP11 state. */
2126b1751ae6SLad Prabhakar 	usleep_range(500, 1000);
2127b1751ae6SLad Prabhakar 
2128b1751ae6SLad Prabhakar 	return 0;
2129b1751ae6SLad Prabhakar }
2130b1751ae6SLad Prabhakar 
2131576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
2132576f5d4bSLad Prabhakar {
2133311a6408SLad Prabhakar 	unsigned int flags = sensor->ep.bus.parallel.flags;
213468579b32SHugues Fruchet 	bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656;
213568579b32SHugues Fruchet 	u8 polarities = 0;
2136576f5d4bSLad Prabhakar 	int ret;
2137576f5d4bSLad Prabhakar 
2138576f5d4bSLad Prabhakar 	if (!on) {
2139576f5d4bSLad Prabhakar 		/* Reset settings to their default values. */
214068579b32SHugues Fruchet 		ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00);
2141311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
2142311a6408SLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
2143576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
2144576f5d4bSLad Prabhakar 		ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
2145576f5d4bSLad Prabhakar 		return 0;
2146576f5d4bSLad Prabhakar 	}
2147576f5d4bSLad Prabhakar 
2148576f5d4bSLad Prabhakar 	/*
2149311a6408SLad Prabhakar 	 * Note about parallel port configuration.
2150311a6408SLad Prabhakar 	 *
2151311a6408SLad Prabhakar 	 * When configured in parallel mode, the OV5640 will
2152311a6408SLad Prabhakar 	 * output 10 bits data on DVP data lines [9:0].
2153311a6408SLad Prabhakar 	 * If only 8 bits data are wanted, the 8 bits data lines
2154311a6408SLad Prabhakar 	 * of the camera interface must be physically connected
2155311a6408SLad Prabhakar 	 * on the DVP data lines [9:2].
2156311a6408SLad Prabhakar 	 *
2157311a6408SLad Prabhakar 	 * Control lines polarity can be configured through
2158311a6408SLad Prabhakar 	 * devicetree endpoint control lines properties.
2159311a6408SLad Prabhakar 	 * If no endpoint control lines properties are set,
2160311a6408SLad Prabhakar 	 * polarity will be as below:
2161311a6408SLad Prabhakar 	 * - VSYNC:	active high
2162311a6408SLad Prabhakar 	 * - HREF:	active low
2163311a6408SLad Prabhakar 	 * - PCLK:	active low
216468579b32SHugues Fruchet 	 *
216568579b32SHugues Fruchet 	 * VSYNC & HREF are not configured if BT656 bus mode is selected
2166311a6408SLad Prabhakar 	 */
216768579b32SHugues Fruchet 
216868579b32SHugues Fruchet 	/*
216968579b32SHugues Fruchet 	 * BT656 embedded synchronization configuration
217068579b32SHugues Fruchet 	 *
217168579b32SHugues Fruchet 	 * CCIR656 CTRL00
217268579b32SHugues Fruchet 	 * - [7]:	SYNC code selection (0: auto generate sync code,
217368579b32SHugues Fruchet 	 *		1: sync code from regs 0x4732-0x4735)
217468579b32SHugues Fruchet 	 * - [6]:	f value in CCIR656 SYNC code when fixed f value
217568579b32SHugues Fruchet 	 * - [5]:	Fixed f value
217668579b32SHugues Fruchet 	 * - [4:3]:	Blank toggle data options (00: data=1'h040/1'h200,
217768579b32SHugues Fruchet 	 *		01: data from regs 0x4736-0x4738, 10: always keep 0)
217868579b32SHugues Fruchet 	 * - [1]:	Clip data disable
217968579b32SHugues Fruchet 	 * - [0]:	CCIR656 mode enable
218068579b32SHugues Fruchet 	 *
218168579b32SHugues Fruchet 	 * Default CCIR656 SAV/EAV mode with default codes
218268579b32SHugues Fruchet 	 * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings:
218368579b32SHugues Fruchet 	 * - CCIR656 mode enable
218468579b32SHugues Fruchet 	 * - auto generation of sync codes
218568579b32SHugues Fruchet 	 * - blank toggle data 1'h040/1'h200
218668579b32SHugues Fruchet 	 * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe)
218768579b32SHugues Fruchet 	 */
218868579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
218968579b32SHugues Fruchet 			       bt656 ? 0x01 : 0x00);
219068579b32SHugues Fruchet 	if (ret)
219168579b32SHugues Fruchet 		return ret;
219268579b32SHugues Fruchet 
2193311a6408SLad Prabhakar 	/*
2194311a6408SLad Prabhakar 	 * configure parallel port control lines polarity
2195311a6408SLad Prabhakar 	 *
2196311a6408SLad Prabhakar 	 * POLARITY CTRL0
2197311a6408SLad Prabhakar 	 * - [5]:	PCLK polarity (0: active low, 1: active high)
2198311a6408SLad Prabhakar 	 * - [1]:	HREF polarity (0: active low, 1: active high)
2199311a6408SLad Prabhakar 	 * - [0]:	VSYNC polarity (mismatch here between
2200311a6408SLad Prabhakar 	 *		datasheet and hardware, 0 is active high
2201311a6408SLad Prabhakar 	 *		and 1 is active low...)
2202311a6408SLad Prabhakar 	 */
220368579b32SHugues Fruchet 	if (!bt656) {
2204311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
220568579b32SHugues Fruchet 			polarities |= BIT(1);
2206311a6408SLad Prabhakar 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
220768579b32SHugues Fruchet 			polarities |= BIT(0);
220868579b32SHugues Fruchet 	}
220968579b32SHugues Fruchet 	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
221068579b32SHugues Fruchet 		polarities |= BIT(5);
2211311a6408SLad Prabhakar 
221268579b32SHugues Fruchet 	ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities);
2213311a6408SLad Prabhakar 	if (ret)
2214311a6408SLad Prabhakar 		return ret;
2215311a6408SLad Prabhakar 
2216311a6408SLad Prabhakar 	/*
221768579b32SHugues Fruchet 	 * powerdown MIPI TX/RX PHY & enable DVP
2218311a6408SLad Prabhakar 	 *
2219311a6408SLad Prabhakar 	 * MIPI CONTROL 00
222068579b32SHugues Fruchet 	 * [4] = 1	: Power down MIPI HS Tx
222168579b32SHugues Fruchet 	 * [3] = 1	: Power down MIPI LS Rx
222268579b32SHugues Fruchet 	 * [2] = 0	: DVP enable (MIPI disable)
2223311a6408SLad Prabhakar 	 */
2224311a6408SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
2225311a6408SLad Prabhakar 	if (ret)
2226311a6408SLad Prabhakar 		return ret;
2227311a6408SLad Prabhakar 
2228311a6408SLad Prabhakar 	/*
2229576f5d4bSLad Prabhakar 	 * enable VSYNC/HREF/PCLK DVP control lines
2230576f5d4bSLad Prabhakar 	 * & D[9:6] DVP data lines
2231576f5d4bSLad Prabhakar 	 *
2232576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 01
2233576f5d4bSLad Prabhakar 	 * - 6:		VSYNC output enable
2234576f5d4bSLad Prabhakar 	 * - 5:		HREF output enable
2235576f5d4bSLad Prabhakar 	 * - 4:		PCLK output enable
2236576f5d4bSLad Prabhakar 	 * - [3:0]:	D[9:6] output enable
2237576f5d4bSLad Prabhakar 	 */
22384039b037SLad Prabhakar 	ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
223968579b32SHugues Fruchet 			       bt656 ? 0x1f : 0x7f);
2240576f5d4bSLad Prabhakar 	if (ret)
2241576f5d4bSLad Prabhakar 		return ret;
2242576f5d4bSLad Prabhakar 
2243576f5d4bSLad Prabhakar 	/*
2244576f5d4bSLad Prabhakar 	 * enable D[5:0] DVP data lines
2245576f5d4bSLad Prabhakar 	 *
2246576f5d4bSLad Prabhakar 	 * PAD OUTPUT ENABLE 02
2247576f5d4bSLad Prabhakar 	 * - [7:2]:	D[5:0] output enable
2248576f5d4bSLad Prabhakar 	 */
2249576f5d4bSLad Prabhakar 	return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
2250576f5d4bSLad Prabhakar }
2251576f5d4bSLad Prabhakar 
22520f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
22530f7acb52SHugues Fruchet {
22540f7acb52SHugues Fruchet 	int ret = 0;
22550f7acb52SHugues Fruchet 
22560f7acb52SHugues Fruchet 	if (on) {
22570f7acb52SHugues Fruchet 		ret = ov5640_set_power_on(sensor);
22580f7acb52SHugues Fruchet 		if (ret)
22590f7acb52SHugues Fruchet 			return ret;
22600f7acb52SHugues Fruchet 
226119a81c14SSteve Longerbeam 		ret = ov5640_restore_mode(sensor);
226219a81c14SSteve Longerbeam 		if (ret)
226319a81c14SSteve Longerbeam 			goto power_off;
2264b1751ae6SLad Prabhakar 	}
226519a81c14SSteve Longerbeam 
2266576f5d4bSLad Prabhakar 	if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
2267b1751ae6SLad Prabhakar 		ret = ov5640_set_power_mipi(sensor, on);
2268576f5d4bSLad Prabhakar 	else
2269576f5d4bSLad Prabhakar 		ret = ov5640_set_power_dvp(sensor, on);
2270b1751ae6SLad Prabhakar 	if (ret)
2271b1751ae6SLad Prabhakar 		goto power_off;
2272aa4bb8b8SJacopo Mondi 
2273b1751ae6SLad Prabhakar 	if (!on)
2274aa4bb8b8SJacopo Mondi 		ov5640_set_power_off(sensor);
227519a81c14SSteve Longerbeam 
227619a81c14SSteve Longerbeam 	return 0;
227719a81c14SSteve Longerbeam 
227819a81c14SSteve Longerbeam power_off:
22790f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
228019a81c14SSteve Longerbeam 	return ret;
228119a81c14SSteve Longerbeam }
228219a81c14SSteve Longerbeam 
228319a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */
228419a81c14SSteve Longerbeam 
228519a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on)
228619a81c14SSteve Longerbeam {
228719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
228819a81c14SSteve Longerbeam 	int ret = 0;
228919a81c14SSteve Longerbeam 
229019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
229119a81c14SSteve Longerbeam 
229219a81c14SSteve Longerbeam 	/*
229319a81c14SSteve Longerbeam 	 * If the power count is modified from 0 to != 0 or from != 0 to 0,
229419a81c14SSteve Longerbeam 	 * update the power state.
229519a81c14SSteve Longerbeam 	 */
229619a81c14SSteve Longerbeam 	if (sensor->power_count == !on) {
229719a81c14SSteve Longerbeam 		ret = ov5640_set_power(sensor, !!on);
229819a81c14SSteve Longerbeam 		if (ret)
229919a81c14SSteve Longerbeam 			goto out;
230019a81c14SSteve Longerbeam 	}
230119a81c14SSteve Longerbeam 
230219a81c14SSteve Longerbeam 	/* Update the power count. */
230319a81c14SSteve Longerbeam 	sensor->power_count += on ? 1 : -1;
230419a81c14SSteve Longerbeam 	WARN_ON(sensor->power_count < 0);
230519a81c14SSteve Longerbeam out:
230619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
230719a81c14SSteve Longerbeam 
230819a81c14SSteve Longerbeam 	if (on && !ret && sensor->power_count == 1) {
230919a81c14SSteve Longerbeam 		/* restore controls */
231019a81c14SSteve Longerbeam 		ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
231119a81c14SSteve Longerbeam 	}
231219a81c14SSteve Longerbeam 
231319a81c14SSteve Longerbeam 	return ret;
231419a81c14SSteve Longerbeam }
231519a81c14SSteve Longerbeam 
231619a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
231719a81c14SSteve Longerbeam 				     struct v4l2_fract *fi,
231819a81c14SSteve Longerbeam 				     u32 width, u32 height)
231919a81c14SSteve Longerbeam {
232019a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
23216530a5ebSJagan Teki 	enum ov5640_frame_rate rate = OV5640_15_FPS;
2322f6cc192fSMaxime Ripard 	int minfps, maxfps, best_fps, fps;
2323f6cc192fSMaxime Ripard 	int i;
232419a81c14SSteve Longerbeam 
232519a81c14SSteve Longerbeam 	minfps = ov5640_framerates[OV5640_15_FPS];
2326e823fb16SMaxime Ripard 	maxfps = ov5640_framerates[OV5640_60_FPS];
232719a81c14SSteve Longerbeam 
232819a81c14SSteve Longerbeam 	if (fi->numerator == 0) {
232919a81c14SSteve Longerbeam 		fi->denominator = maxfps;
233019a81c14SSteve Longerbeam 		fi->numerator = 1;
2331e823fb16SMaxime Ripard 		rate = OV5640_60_FPS;
2332e823fb16SMaxime Ripard 		goto find_mode;
233319a81c14SSteve Longerbeam 	}
233419a81c14SSteve Longerbeam 
2335f6cc192fSMaxime Ripard 	fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
2336f6cc192fSMaxime Ripard 			minfps, maxfps);
2337f6cc192fSMaxime Ripard 
2338f6cc192fSMaxime Ripard 	best_fps = minfps;
2339f6cc192fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
2340f6cc192fSMaxime Ripard 		int curr_fps = ov5640_framerates[i];
2341f6cc192fSMaxime Ripard 
2342f6cc192fSMaxime Ripard 		if (abs(curr_fps - fps) < abs(best_fps - fps)) {
2343f6cc192fSMaxime Ripard 			best_fps = curr_fps;
2344f6cc192fSMaxime Ripard 			rate = i;
2345f6cc192fSMaxime Ripard 		}
2346f6cc192fSMaxime Ripard 	}
234719a81c14SSteve Longerbeam 
234819a81c14SSteve Longerbeam 	fi->numerator = 1;
2349f6cc192fSMaxime Ripard 	fi->denominator = best_fps;
235019a81c14SSteve Longerbeam 
2351e823fb16SMaxime Ripard find_mode:
23525a3ad937SMaxime Ripard 	mode = ov5640_find_mode(sensor, rate, width, height, false);
23535a3ad937SMaxime Ripard 	return mode ? rate : -EINVAL;
235419a81c14SSteve Longerbeam }
235519a81c14SSteve Longerbeam 
235619a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd,
23570d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
235819a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
235919a81c14SSteve Longerbeam {
236019a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
236119a81c14SSteve Longerbeam 	struct v4l2_mbus_framefmt *fmt;
236219a81c14SSteve Longerbeam 
236319a81c14SSteve Longerbeam 	if (format->pad != 0)
236419a81c14SSteve Longerbeam 		return -EINVAL;
236519a81c14SSteve Longerbeam 
236619a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
236719a81c14SSteve Longerbeam 
236819a81c14SSteve Longerbeam 	if (format->which == V4L2_SUBDEV_FORMAT_TRY)
23690d346d2aSTomi Valkeinen 		fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state,
237019a81c14SSteve Longerbeam 						 format->pad);
237119a81c14SSteve Longerbeam 	else
237219a81c14SSteve Longerbeam 		fmt = &sensor->fmt;
237319a81c14SSteve Longerbeam 
237419a81c14SSteve Longerbeam 	format->format = *fmt;
237519a81c14SSteve Longerbeam 
237619a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
237719a81c14SSteve Longerbeam 
237819a81c14SSteve Longerbeam 	return 0;
237919a81c14SSteve Longerbeam }
238019a81c14SSteve Longerbeam 
238119a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
238219a81c14SSteve Longerbeam 				   struct v4l2_mbus_framefmt *fmt,
238319a81c14SSteve Longerbeam 				   enum ov5640_frame_rate fr,
238419a81c14SSteve Longerbeam 				   const struct ov5640_mode_info **new_mode)
238519a81c14SSteve Longerbeam {
238619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
238719a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
2388e3ee691dSHugues Fruchet 	int i;
238919a81c14SSteve Longerbeam 
239019a81c14SSteve Longerbeam 	mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
239119a81c14SSteve Longerbeam 	if (!mode)
239219a81c14SSteve Longerbeam 		return -EINVAL;
2393dba13a0bSMaxime Ripard 	fmt->width = mode->hact;
2394dba13a0bSMaxime Ripard 	fmt->height = mode->vact;
239519a81c14SSteve Longerbeam 
239619a81c14SSteve Longerbeam 	if (new_mode)
239719a81c14SSteve Longerbeam 		*new_mode = mode;
2398e3ee691dSHugues Fruchet 
2399e3ee691dSHugues Fruchet 	for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
2400e3ee691dSHugues Fruchet 		if (ov5640_formats[i].code == fmt->code)
2401e3ee691dSHugues Fruchet 			break;
2402e3ee691dSHugues Fruchet 	if (i >= ARRAY_SIZE(ov5640_formats))
2403e6441fdeSHugues Fruchet 		i = 0;
2404e6441fdeSHugues Fruchet 
2405e6441fdeSHugues Fruchet 	fmt->code = ov5640_formats[i].code;
2406e6441fdeSHugues Fruchet 	fmt->colorspace = ov5640_formats[i].colorspace;
2407e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
2408e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
2409e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
2410e3ee691dSHugues Fruchet 
241119a81c14SSteve Longerbeam 	return 0;
241219a81c14SSteve Longerbeam }
241319a81c14SSteve Longerbeam 
24143c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
24153c28588fSJacopo Mondi {
24163c28588fSJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
24173c28588fSJacopo Mondi 	enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
24183c28588fSJacopo Mondi 	struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
24193c28588fSJacopo Mondi 	unsigned int i = 0;
24203c28588fSJacopo Mondi 	u32 pixel_rate;
24213c28588fSJacopo Mondi 	s64 link_freq;
24223c28588fSJacopo Mondi 	u32 num_lanes;
24233c28588fSJacopo Mondi 	u32 bpp;
24243c28588fSJacopo Mondi 
24253c28588fSJacopo Mondi 	/*
24263c28588fSJacopo Mondi 	 * Update the pixel rate control value.
24273c28588fSJacopo Mondi 	 *
24283c28588fSJacopo Mondi 	 * For DVP mode, maintain the pixel rate calculation using fixed FPS.
24293c28588fSJacopo Mondi 	 */
24303c28588fSJacopo Mondi 	if (!ov5640_is_csi2(sensor)) {
24313c28588fSJacopo Mondi 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
24323c28588fSJacopo Mondi 					 ov5640_calc_pixel_rate(sensor));
24333c28588fSJacopo Mondi 
24343c28588fSJacopo Mondi 		return 0;
24353c28588fSJacopo Mondi 	}
24363c28588fSJacopo Mondi 
24373c28588fSJacopo Mondi 	/*
24383c28588fSJacopo Mondi 	 * The MIPI CSI-2 link frequency should comply with the CSI-2
24393c28588fSJacopo Mondi 	 * specification and be lower than 1GHz.
24403c28588fSJacopo Mondi 	 *
24413c28588fSJacopo Mondi 	 * Start from the suggested pixel_rate for the current mode and
24423c28588fSJacopo Mondi 	 * progressively slow it down if it exceeds 1GHz.
24433c28588fSJacopo Mondi 	 */
24443c28588fSJacopo Mondi 	num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
24453c28588fSJacopo Mondi 	bpp = ov5640_code_to_bpp(fmt->code);
24463c28588fSJacopo Mondi 	do {
24473c28588fSJacopo Mondi 		pixel_rate = ov5640_pixel_rates[pixel_rate_id];
24483c28588fSJacopo Mondi 		link_freq = pixel_rate * bpp / (2 * num_lanes);
24493c28588fSJacopo Mondi 	} while (link_freq >= 1000000000U &&
24503c28588fSJacopo Mondi 		 ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
24513c28588fSJacopo Mondi 
24523c28588fSJacopo Mondi 	sensor->current_link_freq = link_freq;
24533c28588fSJacopo Mondi 
24543c28588fSJacopo Mondi 	/*
24553c28588fSJacopo Mondi 	 * Higher link rates require the clock tree to be programmed with
24563c28588fSJacopo Mondi 	 * 'mipi_div' = 1; this has the effect of halving the actual output
24573c28588fSJacopo Mondi 	 * pixel rate in the MIPI domain.
24583c28588fSJacopo Mondi 	 *
24593c28588fSJacopo Mondi 	 * Adjust the pixel rate and link frequency control value to report it
24603c28588fSJacopo Mondi 	 * correctly to userspace.
24613c28588fSJacopo Mondi 	 */
24623c28588fSJacopo Mondi 	if (link_freq > OV5640_LINK_RATE_MAX) {
24633c28588fSJacopo Mondi 		pixel_rate /= 2;
24643c28588fSJacopo Mondi 		link_freq /= 2;
24653c28588fSJacopo Mondi 	}
24663c28588fSJacopo Mondi 
24673c28588fSJacopo Mondi 	for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
24683c28588fSJacopo Mondi 		if (ov5640_csi2_link_freqs[i] == link_freq)
24693c28588fSJacopo Mondi 			break;
24703c28588fSJacopo Mondi 	}
24713c28588fSJacopo Mondi 	WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
24723c28588fSJacopo Mondi 
24733c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
24743c28588fSJacopo Mondi 	__v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
24753c28588fSJacopo Mondi 
24763c28588fSJacopo Mondi 	return 0;
24773c28588fSJacopo Mondi }
24783c28588fSJacopo Mondi 
247919a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd,
24800d346d2aSTomi Valkeinen 			  struct v4l2_subdev_state *sd_state,
248119a81c14SSteve Longerbeam 			  struct v4l2_subdev_format *format)
248219a81c14SSteve Longerbeam {
248319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
248419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *new_mode;
2485e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
248619a81c14SSteve Longerbeam 	int ret;
248719a81c14SSteve Longerbeam 
248819a81c14SSteve Longerbeam 	if (format->pad != 0)
248919a81c14SSteve Longerbeam 		return -EINVAL;
249019a81c14SSteve Longerbeam 
249119a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
249219a81c14SSteve Longerbeam 
249319a81c14SSteve Longerbeam 	if (sensor->streaming) {
249419a81c14SSteve Longerbeam 		ret = -EBUSY;
249519a81c14SSteve Longerbeam 		goto out;
249619a81c14SSteve Longerbeam 	}
249719a81c14SSteve Longerbeam 
2498e6441fdeSHugues Fruchet 	ret = ov5640_try_fmt_internal(sd, mbus_fmt,
249919a81c14SSteve Longerbeam 				      sensor->current_fr, &new_mode);
250019a81c14SSteve Longerbeam 	if (ret)
250119a81c14SSteve Longerbeam 		goto out;
250219a81c14SSteve Longerbeam 
2503e738f5ddSMirela Rabulea 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
2504e738f5ddSMirela Rabulea 		*v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt;
2505e738f5ddSMirela Rabulea 		goto out;
2506e738f5ddSMirela Rabulea 	}
250719a81c14SSteve Longerbeam 
25086949d864SHugues Fruchet 	if (new_mode != sensor->current_mode) {
250919a81c14SSteve Longerbeam 		sensor->current_mode = new_mode;
251019a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
25116949d864SHugues Fruchet 	}
251207115449SJacopo Mondi 	if (mbus_fmt->code != sensor->fmt.code)
2513fb98e29fSHugues Fruchet 		sensor->pending_fmt_change = true;
251407115449SJacopo Mondi 
2515e738f5ddSMirela Rabulea 	/* update format even if code is unchanged, resolution might change */
2516e738f5ddSMirela Rabulea 	sensor->fmt = *mbus_fmt;
2517e738f5ddSMirela Rabulea 
25183c28588fSJacopo Mondi 	ov5640_update_pixel_rate(sensor);
25193c28588fSJacopo Mondi 
252019a81c14SSteve Longerbeam out:
252119a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
252219a81c14SSteve Longerbeam 	return ret;
252319a81c14SSteve Longerbeam }
252419a81c14SSteve Longerbeam 
2525e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor,
2526e3ee691dSHugues Fruchet 			       struct v4l2_mbus_framefmt *format)
2527e3ee691dSHugues Fruchet {
2528e3ee691dSHugues Fruchet 	int ret = 0;
2529d47c4126SHugues Fruchet 	bool is_jpeg = false;
2530b7ed3abdSLoic Poulain 	u8 fmt, mux;
2531e3ee691dSHugues Fruchet 
2532e3ee691dSHugues Fruchet 	switch (format->code) {
25331536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_UYVY8_1X16:
2534e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_UYVY8_2X8:
2535e3ee691dSHugues Fruchet 		/* YUV422, UYVY */
2536b7ed3abdSLoic Poulain 		fmt = 0x3f;
2537b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2538e3ee691dSHugues Fruchet 		break;
25391536fbdbSXavier Roumegue 	case MEDIA_BUS_FMT_YUYV8_1X16:
2540e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_YUYV8_2X8:
2541e3ee691dSHugues Fruchet 		/* YUV422, YUYV */
2542b7ed3abdSLoic Poulain 		fmt = 0x30;
2543b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2544e3ee691dSHugues Fruchet 		break;
2545e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_LE:
2546e3ee691dSHugues Fruchet 		/* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
2547b7ed3abdSLoic Poulain 		fmt = 0x6F;
2548b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2549e3ee691dSHugues Fruchet 		break;
2550e3ee691dSHugues Fruchet 	case MEDIA_BUS_FMT_RGB565_2X8_BE:
2551e3ee691dSHugues Fruchet 		/* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
2552b7ed3abdSLoic Poulain 		fmt = 0x61;
2553b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RGB;
2554e3ee691dSHugues Fruchet 		break;
2555d47c4126SHugues Fruchet 	case MEDIA_BUS_FMT_JPEG_1X8:
2556d47c4126SHugues Fruchet 		/* YUV422, YUYV */
2557b7ed3abdSLoic Poulain 		fmt = 0x30;
2558b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_YUV422;
2559d47c4126SHugues Fruchet 		is_jpeg = true;
2560d47c4126SHugues Fruchet 		break;
2561b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SBGGR8_1X8:
2562b7ed3abdSLoic Poulain 		/* Raw, BGBG... / GRGR... */
2563b7ed3abdSLoic Poulain 		fmt = 0x00;
2564b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2565b7ed3abdSLoic Poulain 		break;
2566b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGBRG8_1X8:
2567b7ed3abdSLoic Poulain 		/* Raw bayer, GBGB... / RGRG... */
2568b7ed3abdSLoic Poulain 		fmt = 0x01;
2569b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2570b7ed3abdSLoic Poulain 		break;
2571b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SGRBG8_1X8:
2572b7ed3abdSLoic Poulain 		/* Raw bayer, GRGR... / BGBG... */
2573b7ed3abdSLoic Poulain 		fmt = 0x02;
2574b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2575b7ed3abdSLoic Poulain 		break;
2576b7ed3abdSLoic Poulain 	case MEDIA_BUS_FMT_SRGGB8_1X8:
2577b7ed3abdSLoic Poulain 		/* Raw bayer, RGRG... / GBGB... */
2578b7ed3abdSLoic Poulain 		fmt = 0x03;
2579b7ed3abdSLoic Poulain 		mux = OV5640_FMT_MUX_RAW_DPC;
2580b7ed3abdSLoic Poulain 		break;
2581e3ee691dSHugues Fruchet 	default:
2582e3ee691dSHugues Fruchet 		return -EINVAL;
2583e3ee691dSHugues Fruchet 	}
2584e3ee691dSHugues Fruchet 
2585e3ee691dSHugues Fruchet 	/* FORMAT CONTROL00: YUV and RGB formatting */
2586b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
2587e3ee691dSHugues Fruchet 	if (ret)
2588e3ee691dSHugues Fruchet 		return ret;
2589e3ee691dSHugues Fruchet 
2590e3ee691dSHugues Fruchet 	/* FORMAT MUX CONTROL: ISP YUV or RGB */
2591b7ed3abdSLoic Poulain 	ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
2592d47c4126SHugues Fruchet 	if (ret)
2593d47c4126SHugues Fruchet 		return ret;
2594d47c4126SHugues Fruchet 
2595d47c4126SHugues Fruchet 	/*
2596d47c4126SHugues Fruchet 	 * TIMING TC REG21:
2597d47c4126SHugues Fruchet 	 * - [5]:	JPEG enable
2598d47c4126SHugues Fruchet 	 */
2599d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2600d47c4126SHugues Fruchet 			     BIT(5), is_jpeg ? BIT(5) : 0);
2601d47c4126SHugues Fruchet 	if (ret)
2602d47c4126SHugues Fruchet 		return ret;
2603d47c4126SHugues Fruchet 
2604d47c4126SHugues Fruchet 	/*
2605d47c4126SHugues Fruchet 	 * SYSTEM RESET02:
2606d47c4126SHugues Fruchet 	 * - [4]:	Reset JFIFO
2607d47c4126SHugues Fruchet 	 * - [3]:	Reset SFIFO
2608d47c4126SHugues Fruchet 	 * - [2]:	Reset JPEG
2609d47c4126SHugues Fruchet 	 */
2610d47c4126SHugues Fruchet 	ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02,
2611d47c4126SHugues Fruchet 			     BIT(4) | BIT(3) | BIT(2),
2612d47c4126SHugues Fruchet 			     is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2)));
2613d47c4126SHugues Fruchet 	if (ret)
2614d47c4126SHugues Fruchet 		return ret;
2615d47c4126SHugues Fruchet 
2616d47c4126SHugues Fruchet 	/*
2617d47c4126SHugues Fruchet 	 * CLOCK ENABLE02:
2618d47c4126SHugues Fruchet 	 * - [5]:	Enable JPEG 2x clock
2619d47c4126SHugues Fruchet 	 * - [3]:	Enable JPEG clock
2620d47c4126SHugues Fruchet 	 */
2621d47c4126SHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02,
2622d47c4126SHugues Fruchet 			      BIT(5) | BIT(3),
2623d47c4126SHugues Fruchet 			      is_jpeg ? (BIT(5) | BIT(3)) : 0);
2624e3ee691dSHugues Fruchet }
262519a81c14SSteve Longerbeam 
262619a81c14SSteve Longerbeam /*
262719a81c14SSteve Longerbeam  * Sensor Controls.
262819a81c14SSteve Longerbeam  */
262919a81c14SSteve Longerbeam 
263019a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value)
263119a81c14SSteve Longerbeam {
263219a81c14SSteve Longerbeam 	int ret;
263319a81c14SSteve Longerbeam 
263419a81c14SSteve Longerbeam 	if (value) {
263519a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
263619a81c14SSteve Longerbeam 				     BIT(0), BIT(0));
263719a81c14SSteve Longerbeam 		if (ret)
263819a81c14SSteve Longerbeam 			return ret;
263919a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value);
264019a81c14SSteve Longerbeam 	} else {
264119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0);
264219a81c14SSteve Longerbeam 	}
264319a81c14SSteve Longerbeam 
264419a81c14SSteve Longerbeam 	return ret;
264519a81c14SSteve Longerbeam }
264619a81c14SSteve Longerbeam 
264719a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value)
264819a81c14SSteve Longerbeam {
264919a81c14SSteve Longerbeam 	int ret;
265019a81c14SSteve Longerbeam 
265119a81c14SSteve Longerbeam 	if (value) {
265219a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
265319a81c14SSteve Longerbeam 				     BIT(2), BIT(2));
265419a81c14SSteve Longerbeam 		if (ret)
265519a81c14SSteve Longerbeam 			return ret;
265619a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5,
265719a81c14SSteve Longerbeam 				       value & 0xff);
265819a81c14SSteve Longerbeam 	} else {
265919a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0);
266019a81c14SSteve Longerbeam 	}
266119a81c14SSteve Longerbeam 
266219a81c14SSteve Longerbeam 	return ret;
266319a81c14SSteve Longerbeam }
266419a81c14SSteve Longerbeam 
266519a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value)
266619a81c14SSteve Longerbeam {
266719a81c14SSteve Longerbeam 	int ret;
266819a81c14SSteve Longerbeam 
266919a81c14SSteve Longerbeam 	if (value) {
267019a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0,
267119a81c14SSteve Longerbeam 				     BIT(1), BIT(1));
267219a81c14SSteve Longerbeam 		if (ret)
267319a81c14SSteve Longerbeam 			return ret;
267419a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3,
267519a81c14SSteve Longerbeam 				       value & 0xff);
267619a81c14SSteve Longerbeam 		if (ret)
267719a81c14SSteve Longerbeam 			return ret;
267819a81c14SSteve Longerbeam 		ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4,
267919a81c14SSteve Longerbeam 				       value & 0xff);
268019a81c14SSteve Longerbeam 	} else {
268119a81c14SSteve Longerbeam 		ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0);
268219a81c14SSteve Longerbeam 	}
268319a81c14SSteve Longerbeam 
268419a81c14SSteve Longerbeam 	return ret;
268519a81c14SSteve Longerbeam }
268619a81c14SSteve Longerbeam 
268719a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb)
268819a81c14SSteve Longerbeam {
268919a81c14SSteve Longerbeam 	int ret;
269019a81c14SSteve Longerbeam 
269119a81c14SSteve Longerbeam 	ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL,
269219a81c14SSteve Longerbeam 			     BIT(0), awb ? 0 : 1);
269319a81c14SSteve Longerbeam 	if (ret)
269419a81c14SSteve Longerbeam 		return ret;
269519a81c14SSteve Longerbeam 
269619a81c14SSteve Longerbeam 	if (!awb) {
269719a81c14SSteve Longerbeam 		u16 red = (u16)sensor->ctrls.red_balance->val;
269819a81c14SSteve Longerbeam 		u16 blue = (u16)sensor->ctrls.blue_balance->val;
269919a81c14SSteve Longerbeam 
270019a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red);
270119a81c14SSteve Longerbeam 		if (ret)
270219a81c14SSteve Longerbeam 			return ret;
270319a81c14SSteve Longerbeam 		ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue);
270419a81c14SSteve Longerbeam 	}
270519a81c14SSteve Longerbeam 
270619a81c14SSteve Longerbeam 	return ret;
270719a81c14SSteve Longerbeam }
270819a81c14SSteve Longerbeam 
27093cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
27103cca8ef5SHugues Fruchet 				    enum v4l2_exposure_auto_type auto_exposure)
271119a81c14SSteve Longerbeam {
271219a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
27133cca8ef5SHugues Fruchet 	bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO);
271419a81c14SSteve Longerbeam 	int ret = 0;
271519a81c14SSteve Longerbeam 
271619a81c14SSteve Longerbeam 	if (ctrls->auto_exp->is_new) {
27173cca8ef5SHugues Fruchet 		ret = ov5640_set_autoexposure(sensor, auto_exp);
271819a81c14SSteve Longerbeam 		if (ret)
271919a81c14SSteve Longerbeam 			return ret;
272019a81c14SSteve Longerbeam 	}
272119a81c14SSteve Longerbeam 
27223cca8ef5SHugues Fruchet 	if (!auto_exp && ctrls->exposure->is_new) {
272319a81c14SSteve Longerbeam 		u16 max_exp;
272419a81c14SSteve Longerbeam 
272519a81c14SSteve Longerbeam 		ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS,
272619a81c14SSteve Longerbeam 					&max_exp);
272719a81c14SSteve Longerbeam 		if (ret)
272819a81c14SSteve Longerbeam 			return ret;
272919a81c14SSteve Longerbeam 		ret = ov5640_get_vts(sensor);
273019a81c14SSteve Longerbeam 		if (ret < 0)
273119a81c14SSteve Longerbeam 			return ret;
273219a81c14SSteve Longerbeam 		max_exp += ret;
27336146fde3SHugues Fruchet 		ret = 0;
273419a81c14SSteve Longerbeam 
273519a81c14SSteve Longerbeam 		if (ctrls->exposure->val < max_exp)
273619a81c14SSteve Longerbeam 			ret = ov5640_set_exposure(sensor, ctrls->exposure->val);
273719a81c14SSteve Longerbeam 	}
273819a81c14SSteve Longerbeam 
273919a81c14SSteve Longerbeam 	return ret;
274019a81c14SSteve Longerbeam }
274119a81c14SSteve Longerbeam 
27423cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
274319a81c14SSteve Longerbeam {
274419a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
274519a81c14SSteve Longerbeam 	int ret = 0;
274619a81c14SSteve Longerbeam 
274719a81c14SSteve Longerbeam 	if (ctrls->auto_gain->is_new) {
27483cca8ef5SHugues Fruchet 		ret = ov5640_set_autogain(sensor, auto_gain);
274919a81c14SSteve Longerbeam 		if (ret)
275019a81c14SSteve Longerbeam 			return ret;
275119a81c14SSteve Longerbeam 	}
275219a81c14SSteve Longerbeam 
27533cca8ef5SHugues Fruchet 	if (!auto_gain && ctrls->gain->is_new)
27543cca8ef5SHugues Fruchet 		ret = ov5640_set_gain(sensor, ctrls->gain->val);
275519a81c14SSteve Longerbeam 
275619a81c14SSteve Longerbeam 	return ret;
275719a81c14SSteve Longerbeam }
275819a81c14SSteve Longerbeam 
27599f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = {
27609f6d7bacSChen-Yu Tsai 	"Disabled",
27619f6d7bacSChen-Yu Tsai 	"Color bars",
2762bddc5cdfSChen-Yu Tsai 	"Color bars w/ rolling bar",
2763bddc5cdfSChen-Yu Tsai 	"Color squares",
2764bddc5cdfSChen-Yu Tsai 	"Color squares w/ rolling bar",
27659f6d7bacSChen-Yu Tsai };
27669f6d7bacSChen-Yu Tsai 
2767a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE		BIT(7)
2768a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING		BIT(6)	/* rolling horizontal bar */
2769a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT		BIT(5)
2770a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW		BIT(4)	/* black & white squares */
2771a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD	(0 << 2)
2772a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1	(1 << 2)
2773a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE	(2 << 2)
2774a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2	(3 << 2)
2775a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR			(0 << 0)
2776a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM		(1 << 0)
2777a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE		(2 << 0)
2778a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK		(3 << 0)
2779a0c29afbSChen-Yu Tsai 
2780a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = {
2781a0c29afbSChen-Yu Tsai 	0,
27822aff1fc3SChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 |
2783a0c29afbSChen-Yu Tsai 		OV5640_TEST_BAR,
2784bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING |
2785bddc5cdfSChen-Yu Tsai 		OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR,
2786bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_SQUARE,
2787bddc5cdfSChen-Yu Tsai 	OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE,
2788a0c29afbSChen-Yu Tsai };
2789a0c29afbSChen-Yu Tsai 
279019a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
279119a81c14SSteve Longerbeam {
2792a0c29afbSChen-Yu Tsai 	return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1,
2793a0c29afbSChen-Yu Tsai 				test_pattern_val[value]);
279419a81c14SSteve Longerbeam }
279519a81c14SSteve Longerbeam 
27961068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
27971068fecaSMylène Josserand {
27981068fecaSMylène Josserand 	int ret;
27991068fecaSMylène Josserand 
28001068fecaSMylène Josserand 	ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
28011068fecaSMylène Josserand 			     (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
28021068fecaSMylène Josserand 			     0 : BIT(7));
28031068fecaSMylène Josserand 	if (ret)
28041068fecaSMylène Josserand 		return ret;
28051068fecaSMylène Josserand 
28061068fecaSMylène Josserand 	return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
28071068fecaSMylène Josserand 			      (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
28081068fecaSMylène Josserand 			      BIT(2) : 0);
28091068fecaSMylène Josserand }
28101068fecaSMylène Josserand 
2811ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
2812ce85705aSHugues Fruchet {
2813ce85705aSHugues Fruchet 	/*
2814c3f3ba3eSHugues Fruchet 	 * If sensor is mounted upside down, mirror logic is inversed.
2815c3f3ba3eSHugues Fruchet 	 *
2816ce85705aSHugues Fruchet 	 * Sensor is a BSI (Back Side Illuminated) one,
2817ce85705aSHugues Fruchet 	 * so image captured is physically mirrored.
2818ce85705aSHugues Fruchet 	 * This is why mirror logic is inversed in
2819ce85705aSHugues Fruchet 	 * order to cancel this mirror effect.
2820ce85705aSHugues Fruchet 	 */
2821ce85705aSHugues Fruchet 
2822ce85705aSHugues Fruchet 	/*
2823ce85705aSHugues Fruchet 	 * TIMING TC REG21:
2824ce85705aSHugues Fruchet 	 * - [2]:	ISP mirror
2825ce85705aSHugues Fruchet 	 * - [1]:	Sensor mirror
2826ce85705aSHugues Fruchet 	 */
2827ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
2828ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
2829c3f3ba3eSHugues Fruchet 			      (!(value ^ sensor->upside_down)) ?
2830c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
2831ce85705aSHugues Fruchet }
2832ce85705aSHugues Fruchet 
2833ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
2834ce85705aSHugues Fruchet {
2835c3f3ba3eSHugues Fruchet 	/* If sensor is mounted upside down, flip logic is inversed */
2836c3f3ba3eSHugues Fruchet 
2837ce85705aSHugues Fruchet 	/*
2838ce85705aSHugues Fruchet 	 * TIMING TC REG20:
2839ce85705aSHugues Fruchet 	 * - [2]:	ISP vflip
2840ce85705aSHugues Fruchet 	 * - [1]:	Sensor vflip
2841ce85705aSHugues Fruchet 	 */
2842ce85705aSHugues Fruchet 	return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
2843ce85705aSHugues Fruchet 			      BIT(2) | BIT(1),
2844c3f3ba3eSHugues Fruchet 			      (value ^ sensor->upside_down) ?
2845c3f3ba3eSHugues Fruchet 			      (BIT(2) | BIT(1)) : 0);
2846ce85705aSHugues Fruchet }
2847ce85705aSHugues Fruchet 
284819a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
284919a81c14SSteve Longerbeam {
285019a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
285119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
285219a81c14SSteve Longerbeam 	int val;
285319a81c14SSteve Longerbeam 
285419a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
285519a81c14SSteve Longerbeam 
285619a81c14SSteve Longerbeam 	switch (ctrl->id) {
285719a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
285819a81c14SSteve Longerbeam 		val = ov5640_get_gain(sensor);
285919a81c14SSteve Longerbeam 		if (val < 0)
286019a81c14SSteve Longerbeam 			return val;
286119a81c14SSteve Longerbeam 		sensor->ctrls.gain->val = val;
286219a81c14SSteve Longerbeam 		break;
286319a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
286419a81c14SSteve Longerbeam 		val = ov5640_get_exposure(sensor);
286519a81c14SSteve Longerbeam 		if (val < 0)
286619a81c14SSteve Longerbeam 			return val;
286719a81c14SSteve Longerbeam 		sensor->ctrls.exposure->val = val;
286819a81c14SSteve Longerbeam 		break;
286919a81c14SSteve Longerbeam 	}
287019a81c14SSteve Longerbeam 
287119a81c14SSteve Longerbeam 	return 0;
287219a81c14SSteve Longerbeam }
287319a81c14SSteve Longerbeam 
287419a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
287519a81c14SSteve Longerbeam {
287619a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
287719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
287819a81c14SSteve Longerbeam 	int ret;
287919a81c14SSteve Longerbeam 
288019a81c14SSteve Longerbeam 	/* v4l2_ctrl_lock() locks our own mutex */
288119a81c14SSteve Longerbeam 
288219a81c14SSteve Longerbeam 	/*
288319a81c14SSteve Longerbeam 	 * If the device is not powered up by the host driver do
288419a81c14SSteve Longerbeam 	 * not apply any controls to H/W at this time. Instead
288519a81c14SSteve Longerbeam 	 * the controls will be restored right after power-up.
288619a81c14SSteve Longerbeam 	 */
288719a81c14SSteve Longerbeam 	if (sensor->power_count == 0)
288819a81c14SSteve Longerbeam 		return 0;
288919a81c14SSteve Longerbeam 
289019a81c14SSteve Longerbeam 	switch (ctrl->id) {
289119a81c14SSteve Longerbeam 	case V4L2_CID_AUTOGAIN:
289219a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_gain(sensor, ctrl->val);
289319a81c14SSteve Longerbeam 		break;
289419a81c14SSteve Longerbeam 	case V4L2_CID_EXPOSURE_AUTO:
289519a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_exposure(sensor, ctrl->val);
289619a81c14SSteve Longerbeam 		break;
289719a81c14SSteve Longerbeam 	case V4L2_CID_AUTO_WHITE_BALANCE:
289819a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
289919a81c14SSteve Longerbeam 		break;
290019a81c14SSteve Longerbeam 	case V4L2_CID_HUE:
290119a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
290219a81c14SSteve Longerbeam 		break;
290319a81c14SSteve Longerbeam 	case V4L2_CID_CONTRAST:
290419a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_contrast(sensor, ctrl->val);
290519a81c14SSteve Longerbeam 		break;
290619a81c14SSteve Longerbeam 	case V4L2_CID_SATURATION:
290719a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_saturation(sensor, ctrl->val);
290819a81c14SSteve Longerbeam 		break;
290919a81c14SSteve Longerbeam 	case V4L2_CID_TEST_PATTERN:
291019a81c14SSteve Longerbeam 		ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
291119a81c14SSteve Longerbeam 		break;
29121068fecaSMylène Josserand 	case V4L2_CID_POWER_LINE_FREQUENCY:
29131068fecaSMylène Josserand 		ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
29141068fecaSMylène Josserand 		break;
2915ce85705aSHugues Fruchet 	case V4L2_CID_HFLIP:
2916ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_hflip(sensor, ctrl->val);
2917ce85705aSHugues Fruchet 		break;
2918ce85705aSHugues Fruchet 	case V4L2_CID_VFLIP:
2919ce85705aSHugues Fruchet 		ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
2920ce85705aSHugues Fruchet 		break;
292119a81c14SSteve Longerbeam 	default:
292219a81c14SSteve Longerbeam 		ret = -EINVAL;
292319a81c14SSteve Longerbeam 		break;
292419a81c14SSteve Longerbeam 	}
292519a81c14SSteve Longerbeam 
292619a81c14SSteve Longerbeam 	return ret;
292719a81c14SSteve Longerbeam }
292819a81c14SSteve Longerbeam 
292919a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
293019a81c14SSteve Longerbeam 	.g_volatile_ctrl = ov5640_g_volatile_ctrl,
293119a81c14SSteve Longerbeam 	.s_ctrl = ov5640_s_ctrl,
293219a81c14SSteve Longerbeam };
293319a81c14SSteve Longerbeam 
293419a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor)
293519a81c14SSteve Longerbeam {
293622845bf2SJacopo Mondi 	const struct ov5640_mode_info *mode = sensor->current_mode;
293719a81c14SSteve Longerbeam 	const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
293819a81c14SSteve Longerbeam 	struct ov5640_ctrls *ctrls = &sensor->ctrls;
293919a81c14SSteve Longerbeam 	struct v4l2_ctrl_handler *hdl = &ctrls->handler;
294019a81c14SSteve Longerbeam 	int ret;
294119a81c14SSteve Longerbeam 
294219a81c14SSteve Longerbeam 	v4l2_ctrl_handler_init(hdl, 32);
294319a81c14SSteve Longerbeam 
294419a81c14SSteve Longerbeam 	/* we can use our own mutex for the ctrl lock */
294519a81c14SSteve Longerbeam 	hdl->lock = &sensor->lock;
294619a81c14SSteve Longerbeam 
2947cc196e48SBenoit Parrot 	/* Clock related controls */
2948cc196e48SBenoit Parrot 	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
294922845bf2SJacopo Mondi 			      ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
295022845bf2SJacopo Mondi 			      ov5640_pixel_rates[0], 1,
295122845bf2SJacopo Mondi 			      ov5640_pixel_rates[mode->pixel_rate]);
2952cc196e48SBenoit Parrot 
29537a3b8d4bSJacopo Mondi 	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
29547a3b8d4bSJacopo Mondi 					V4L2_CID_LINK_FREQ,
29557a3b8d4bSJacopo Mondi 					ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
29567a3b8d4bSJacopo Mondi 					OV5640_DEFAULT_LINK_FREQ,
29577a3b8d4bSJacopo Mondi 					ov5640_csi2_link_freqs);
29587a3b8d4bSJacopo Mondi 
295919a81c14SSteve Longerbeam 	/* Auto/manual white balance */
296019a81c14SSteve Longerbeam 	ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
296119a81c14SSteve Longerbeam 					   V4L2_CID_AUTO_WHITE_BALANCE,
296219a81c14SSteve Longerbeam 					   0, 1, 1, 1);
296319a81c14SSteve Longerbeam 	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
296419a81c14SSteve Longerbeam 						0, 4095, 1, 0);
296519a81c14SSteve Longerbeam 	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
296619a81c14SSteve Longerbeam 					       0, 4095, 1, 0);
296719a81c14SSteve Longerbeam 	/* Auto/manual exposure */
296819a81c14SSteve Longerbeam 	ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
296919a81c14SSteve Longerbeam 						 V4L2_CID_EXPOSURE_AUTO,
297019a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_MANUAL, 0,
297119a81c14SSteve Longerbeam 						 V4L2_EXPOSURE_AUTO);
297219a81c14SSteve Longerbeam 	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
297319a81c14SSteve Longerbeam 					    0, 65535, 1, 0);
297419a81c14SSteve Longerbeam 	/* Auto/manual gain */
297519a81c14SSteve Longerbeam 	ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN,
297619a81c14SSteve Longerbeam 					     0, 1, 1, 1);
297719a81c14SSteve Longerbeam 	ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
297819a81c14SSteve Longerbeam 					0, 1023, 1, 0);
297919a81c14SSteve Longerbeam 
298019a81c14SSteve Longerbeam 	ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
298119a81c14SSteve Longerbeam 					      0, 255, 1, 64);
298219a81c14SSteve Longerbeam 	ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
298319a81c14SSteve Longerbeam 				       0, 359, 1, 0);
298419a81c14SSteve Longerbeam 	ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST,
298519a81c14SSteve Longerbeam 					    0, 255, 1, 0);
298619a81c14SSteve Longerbeam 	ctrls->test_pattern =
298719a81c14SSteve Longerbeam 		v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
298819a81c14SSteve Longerbeam 					     ARRAY_SIZE(test_pattern_menu) - 1,
298919a81c14SSteve Longerbeam 					     0, 0, test_pattern_menu);
2990ce85705aSHugues Fruchet 	ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP,
2991ce85705aSHugues Fruchet 					 0, 1, 1, 0);
2992ce85705aSHugues Fruchet 	ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP,
2993ce85705aSHugues Fruchet 					 0, 1, 1, 0);
299419a81c14SSteve Longerbeam 
29951068fecaSMylène Josserand 	ctrls->light_freq =
29961068fecaSMylène Josserand 		v4l2_ctrl_new_std_menu(hdl, ops,
29971068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY,
29981068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
29991068fecaSMylène Josserand 				       V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
30001068fecaSMylène Josserand 
300119a81c14SSteve Longerbeam 	if (hdl->error) {
300219a81c14SSteve Longerbeam 		ret = hdl->error;
300319a81c14SSteve Longerbeam 		goto free_ctrls;
300419a81c14SSteve Longerbeam 	}
300519a81c14SSteve Longerbeam 
3006cc196e48SBenoit Parrot 	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
30077a3b8d4bSJacopo Mondi 	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
300819a81c14SSteve Longerbeam 	ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
300919a81c14SSteve Longerbeam 	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
301019a81c14SSteve Longerbeam 
301119a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
301219a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
301319a81c14SSteve Longerbeam 	v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
301419a81c14SSteve Longerbeam 
301519a81c14SSteve Longerbeam 	sensor->sd.ctrl_handler = hdl;
301619a81c14SSteve Longerbeam 	return 0;
301719a81c14SSteve Longerbeam 
301819a81c14SSteve Longerbeam free_ctrls:
301919a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(hdl);
302019a81c14SSteve Longerbeam 	return ret;
302119a81c14SSteve Longerbeam }
302219a81c14SSteve Longerbeam 
302319a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
30240d346d2aSTomi Valkeinen 				  struct v4l2_subdev_state *sd_state,
302519a81c14SSteve Longerbeam 				  struct v4l2_subdev_frame_size_enum *fse)
302619a81c14SSteve Longerbeam {
302719a81c14SSteve Longerbeam 	if (fse->pad != 0)
302819a81c14SSteve Longerbeam 		return -EINVAL;
302919a81c14SSteve Longerbeam 	if (fse->index >= OV5640_NUM_MODES)
303019a81c14SSteve Longerbeam 		return -EINVAL;
303119a81c14SSteve Longerbeam 
303241d8d7f5SHugues Fruchet 	fse->min_width =
3033086c25f8SMaxime Ripard 		ov5640_mode_data[fse->index].hact;
303441d8d7f5SHugues Fruchet 	fse->max_width = fse->min_width;
303541d8d7f5SHugues Fruchet 	fse->min_height =
3036086c25f8SMaxime Ripard 		ov5640_mode_data[fse->index].vact;
303741d8d7f5SHugues Fruchet 	fse->max_height = fse->min_height;
303819a81c14SSteve Longerbeam 
303919a81c14SSteve Longerbeam 	return 0;
304019a81c14SSteve Longerbeam }
304119a81c14SSteve Longerbeam 
304219a81c14SSteve Longerbeam static int ov5640_enum_frame_interval(
304319a81c14SSteve Longerbeam 	struct v4l2_subdev *sd,
30440d346d2aSTomi Valkeinen 	struct v4l2_subdev_state *sd_state,
304519a81c14SSteve Longerbeam 	struct v4l2_subdev_frame_interval_enum *fie)
304619a81c14SSteve Longerbeam {
304719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
304819a81c14SSteve Longerbeam 	struct v4l2_fract tpf;
304919a81c14SSteve Longerbeam 	int ret;
305019a81c14SSteve Longerbeam 
305119a81c14SSteve Longerbeam 	if (fie->pad != 0)
305219a81c14SSteve Longerbeam 		return -EINVAL;
305319a81c14SSteve Longerbeam 	if (fie->index >= OV5640_NUM_FRAMERATES)
305419a81c14SSteve Longerbeam 		return -EINVAL;
305519a81c14SSteve Longerbeam 
305619a81c14SSteve Longerbeam 	tpf.numerator = 1;
305719a81c14SSteve Longerbeam 	tpf.denominator = ov5640_framerates[fie->index];
305819a81c14SSteve Longerbeam 
305919a81c14SSteve Longerbeam 	ret = ov5640_try_frame_interval(sensor, &tpf,
306019a81c14SSteve Longerbeam 					fie->width, fie->height);
306119a81c14SSteve Longerbeam 	if (ret < 0)
306219a81c14SSteve Longerbeam 		return -EINVAL;
306319a81c14SSteve Longerbeam 
306419a81c14SSteve Longerbeam 	fie->interval = tpf;
306519a81c14SSteve Longerbeam 	return 0;
306619a81c14SSteve Longerbeam }
306719a81c14SSteve Longerbeam 
306819a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd,
306919a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
307019a81c14SSteve Longerbeam {
307119a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
307219a81c14SSteve Longerbeam 
307319a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
307419a81c14SSteve Longerbeam 	fi->interval = sensor->frame_interval;
307519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
307619a81c14SSteve Longerbeam 
307719a81c14SSteve Longerbeam 	return 0;
307819a81c14SSteve Longerbeam }
307919a81c14SSteve Longerbeam 
308019a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
308119a81c14SSteve Longerbeam 				   struct v4l2_subdev_frame_interval *fi)
308219a81c14SSteve Longerbeam {
308319a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
308419a81c14SSteve Longerbeam 	const struct ov5640_mode_info *mode;
308519a81c14SSteve Longerbeam 	int frame_rate, ret = 0;
308619a81c14SSteve Longerbeam 
308719a81c14SSteve Longerbeam 	if (fi->pad != 0)
308819a81c14SSteve Longerbeam 		return -EINVAL;
308919a81c14SSteve Longerbeam 
309019a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
309119a81c14SSteve Longerbeam 
309219a81c14SSteve Longerbeam 	if (sensor->streaming) {
309319a81c14SSteve Longerbeam 		ret = -EBUSY;
309419a81c14SSteve Longerbeam 		goto out;
309519a81c14SSteve Longerbeam 	}
309619a81c14SSteve Longerbeam 
309719a81c14SSteve Longerbeam 	mode = sensor->current_mode;
309819a81c14SSteve Longerbeam 
309919a81c14SSteve Longerbeam 	frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
3100dba13a0bSMaxime Ripard 					       mode->hact, mode->vact);
3101e823fb16SMaxime Ripard 	if (frame_rate < 0) {
3102e823fb16SMaxime Ripard 		/* Always return a valid frame interval value */
3103e823fb16SMaxime Ripard 		fi->interval = sensor->frame_interval;
3104e823fb16SMaxime Ripard 		goto out;
3105e823fb16SMaxime Ripard 	}
310619a81c14SSteve Longerbeam 
31073c4a7372SHugues Fruchet 	mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
3108dba13a0bSMaxime Ripard 				mode->vact, true);
31093c4a7372SHugues Fruchet 	if (!mode) {
31103c4a7372SHugues Fruchet 		ret = -EINVAL;
31113c4a7372SHugues Fruchet 		goto out;
31123c4a7372SHugues Fruchet 	}
31133c4a7372SHugues Fruchet 
31140929983eSHugues Fruchet 	if (mode != sensor->current_mode ||
31150929983eSHugues Fruchet 	    frame_rate != sensor->current_fr) {
31160929983eSHugues Fruchet 		sensor->current_fr = frame_rate;
31170929983eSHugues Fruchet 		sensor->frame_interval = fi->interval;
31183c4a7372SHugues Fruchet 		sensor->current_mode = mode;
311919a81c14SSteve Longerbeam 		sensor->pending_mode_change = true;
3120cc196e48SBenoit Parrot 
3121cc196e48SBenoit Parrot 		__v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
3122cc196e48SBenoit Parrot 					 ov5640_calc_pixel_rate(sensor));
31236949d864SHugues Fruchet 	}
312419a81c14SSteve Longerbeam out:
312519a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
312619a81c14SSteve Longerbeam 	return ret;
312719a81c14SSteve Longerbeam }
312819a81c14SSteve Longerbeam 
312919a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
31300d346d2aSTomi Valkeinen 				 struct v4l2_subdev_state *sd_state,
313119a81c14SSteve Longerbeam 				 struct v4l2_subdev_mbus_code_enum *code)
313219a81c14SSteve Longerbeam {
313319a81c14SSteve Longerbeam 	if (code->pad != 0)
313419a81c14SSteve Longerbeam 		return -EINVAL;
3135e3ee691dSHugues Fruchet 	if (code->index >= ARRAY_SIZE(ov5640_formats))
313619a81c14SSteve Longerbeam 		return -EINVAL;
313719a81c14SSteve Longerbeam 
3138e3ee691dSHugues Fruchet 	code->code = ov5640_formats[code->index].code;
313919a81c14SSteve Longerbeam 	return 0;
314019a81c14SSteve Longerbeam }
314119a81c14SSteve Longerbeam 
314219a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
314319a81c14SSteve Longerbeam {
314419a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
314519a81c14SSteve Longerbeam 	int ret = 0;
314619a81c14SSteve Longerbeam 
314719a81c14SSteve Longerbeam 	mutex_lock(&sensor->lock);
314819a81c14SSteve Longerbeam 
314919a81c14SSteve Longerbeam 	if (sensor->streaming == !enable) {
315019a81c14SSteve Longerbeam 		if (enable && sensor->pending_mode_change) {
3151985cdcb0SHugues Fruchet 			ret = ov5640_set_mode(sensor);
315219a81c14SSteve Longerbeam 			if (ret)
315319a81c14SSteve Longerbeam 				goto out;
3154fb98e29fSHugues Fruchet 		}
3155e3ee691dSHugues Fruchet 
3156fb98e29fSHugues Fruchet 		if (enable && sensor->pending_fmt_change) {
3157e3ee691dSHugues Fruchet 			ret = ov5640_set_framefmt(sensor, &sensor->fmt);
3158e3ee691dSHugues Fruchet 			if (ret)
3159e3ee691dSHugues Fruchet 				goto out;
3160fb98e29fSHugues Fruchet 			sensor->pending_fmt_change = false;
316119a81c14SSteve Longerbeam 		}
316219a81c14SSteve Longerbeam 
31638e823f5cSJacopo Mondi 		if (ov5640_is_csi2(sensor))
3164f22996dbSHugues Fruchet 			ret = ov5640_set_stream_mipi(sensor, enable);
3165f22996dbSHugues Fruchet 		else
3166f22996dbSHugues Fruchet 			ret = ov5640_set_stream_dvp(sensor, enable);
3167f22996dbSHugues Fruchet 
316819a81c14SSteve Longerbeam 		if (!ret)
316919a81c14SSteve Longerbeam 			sensor->streaming = enable;
317019a81c14SSteve Longerbeam 	}
317119a81c14SSteve Longerbeam out:
317219a81c14SSteve Longerbeam 	mutex_unlock(&sensor->lock);
317319a81c14SSteve Longerbeam 	return ret;
317419a81c14SSteve Longerbeam }
317519a81c14SSteve Longerbeam 
317619a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = {
317719a81c14SSteve Longerbeam 	.s_power = ov5640_s_power,
31782d18fbc5SAkinobu Mita 	.log_status = v4l2_ctrl_subdev_log_status,
31792d18fbc5SAkinobu Mita 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
31802d18fbc5SAkinobu Mita 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
318119a81c14SSteve Longerbeam };
318219a81c14SSteve Longerbeam 
318319a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = {
318419a81c14SSteve Longerbeam 	.g_frame_interval = ov5640_g_frame_interval,
318519a81c14SSteve Longerbeam 	.s_frame_interval = ov5640_s_frame_interval,
318619a81c14SSteve Longerbeam 	.s_stream = ov5640_s_stream,
318719a81c14SSteve Longerbeam };
318819a81c14SSteve Longerbeam 
318919a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
319019a81c14SSteve Longerbeam 	.enum_mbus_code = ov5640_enum_mbus_code,
319119a81c14SSteve Longerbeam 	.get_fmt = ov5640_get_fmt,
319219a81c14SSteve Longerbeam 	.set_fmt = ov5640_set_fmt,
319319a81c14SSteve Longerbeam 	.enum_frame_size = ov5640_enum_frame_size,
319419a81c14SSteve Longerbeam 	.enum_frame_interval = ov5640_enum_frame_interval,
319519a81c14SSteve Longerbeam };
319619a81c14SSteve Longerbeam 
319719a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = {
319819a81c14SSteve Longerbeam 	.core = &ov5640_core_ops,
319919a81c14SSteve Longerbeam 	.video = &ov5640_video_ops,
320019a81c14SSteve Longerbeam 	.pad = &ov5640_pad_ops,
320119a81c14SSteve Longerbeam };
320219a81c14SSteve Longerbeam 
320319a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor)
320419a81c14SSteve Longerbeam {
320519a81c14SSteve Longerbeam 	int i;
320619a81c14SSteve Longerbeam 
320719a81c14SSteve Longerbeam 	for (i = 0; i < OV5640_NUM_SUPPLIES; i++)
320819a81c14SSteve Longerbeam 		sensor->supplies[i].supply = ov5640_supply_name[i];
320919a81c14SSteve Longerbeam 
321019a81c14SSteve Longerbeam 	return devm_regulator_bulk_get(&sensor->i2c_client->dev,
321119a81c14SSteve Longerbeam 				       OV5640_NUM_SUPPLIES,
321219a81c14SSteve Longerbeam 				       sensor->supplies);
321319a81c14SSteve Longerbeam }
321419a81c14SSteve Longerbeam 
32150f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor)
32160f7acb52SHugues Fruchet {
32170f7acb52SHugues Fruchet 	struct i2c_client *client = sensor->i2c_client;
32180f7acb52SHugues Fruchet 	int ret = 0;
32190f7acb52SHugues Fruchet 	u16 chip_id;
32200f7acb52SHugues Fruchet 
32210f7acb52SHugues Fruchet 	ret = ov5640_set_power_on(sensor);
32220f7acb52SHugues Fruchet 	if (ret)
32230f7acb52SHugues Fruchet 		return ret;
32240f7acb52SHugues Fruchet 
32250f7acb52SHugues Fruchet 	ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
32260f7acb52SHugues Fruchet 	if (ret) {
32270f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: failed to read chip identifier\n",
32280f7acb52SHugues Fruchet 			__func__);
32290f7acb52SHugues Fruchet 		goto power_off;
32300f7acb52SHugues Fruchet 	}
32310f7acb52SHugues Fruchet 
32320f7acb52SHugues Fruchet 	if (chip_id != 0x5640) {
32330f7acb52SHugues Fruchet 		dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
32340f7acb52SHugues Fruchet 			__func__, chip_id);
32350f7acb52SHugues Fruchet 		ret = -ENXIO;
32360f7acb52SHugues Fruchet 	}
32370f7acb52SHugues Fruchet 
32380f7acb52SHugues Fruchet power_off:
32390f7acb52SHugues Fruchet 	ov5640_set_power_off(sensor);
32400f7acb52SHugues Fruchet 	return ret;
32410f7acb52SHugues Fruchet }
32420f7acb52SHugues Fruchet 
3243e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client)
324419a81c14SSteve Longerbeam {
324519a81c14SSteve Longerbeam 	struct device *dev = &client->dev;
324619a81c14SSteve Longerbeam 	struct fwnode_handle *endpoint;
324719a81c14SSteve Longerbeam 	struct ov5640_dev *sensor;
3248e6441fdeSHugues Fruchet 	struct v4l2_mbus_framefmt *fmt;
3249c3f3ba3eSHugues Fruchet 	u32 rotation;
325019a81c14SSteve Longerbeam 	int ret;
325119a81c14SSteve Longerbeam 
325219a81c14SSteve Longerbeam 	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
325319a81c14SSteve Longerbeam 	if (!sensor)
325419a81c14SSteve Longerbeam 		return -ENOMEM;
325519a81c14SSteve Longerbeam 
325619a81c14SSteve Longerbeam 	sensor->i2c_client = client;
3257fb98e29fSHugues Fruchet 
3258fb98e29fSHugues Fruchet 	/*
3259fb98e29fSHugues Fruchet 	 * default init sequence initialize sensor to
3260fb98e29fSHugues Fruchet 	 * YUV422 UYVY VGA@30fps
3261fb98e29fSHugues Fruchet 	 */
3262e6441fdeSHugues Fruchet 	fmt = &sensor->fmt;
3263fb98e29fSHugues Fruchet 	fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
3264fb98e29fSHugues Fruchet 	fmt->colorspace = V4L2_COLORSPACE_SRGB;
3265e6441fdeSHugues Fruchet 	fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
3266e6441fdeSHugues Fruchet 	fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
3267e6441fdeSHugues Fruchet 	fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
3268e6441fdeSHugues Fruchet 	fmt->width = 640;
3269e6441fdeSHugues Fruchet 	fmt->height = 480;
3270e6441fdeSHugues Fruchet 	fmt->field = V4L2_FIELD_NONE;
327119a81c14SSteve Longerbeam 	sensor->frame_interval.numerator = 1;
327219a81c14SSteve Longerbeam 	sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
327319a81c14SSteve Longerbeam 	sensor->current_fr = OV5640_30_FPS;
327419a81c14SSteve Longerbeam 	sensor->current_mode =
3275086c25f8SMaxime Ripard 		&ov5640_mode_data[OV5640_MODE_VGA_640_480];
3276985cdcb0SHugues Fruchet 	sensor->last_mode = sensor->current_mode;
32773c28588fSJacopo Mondi 	sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
327819a81c14SSteve Longerbeam 
327919a81c14SSteve Longerbeam 	sensor->ae_target = 52;
328019a81c14SSteve Longerbeam 
3281c3f3ba3eSHugues Fruchet 	/* optional indication of physical rotation of sensor */
3282c3f3ba3eSHugues Fruchet 	ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
3283c3f3ba3eSHugues Fruchet 				       &rotation);
3284c3f3ba3eSHugues Fruchet 	if (!ret) {
3285c3f3ba3eSHugues Fruchet 		switch (rotation) {
3286c3f3ba3eSHugues Fruchet 		case 180:
3287c3f3ba3eSHugues Fruchet 			sensor->upside_down = true;
32881771e9fbSGustavo A. R. Silva 			fallthrough;
3289c3f3ba3eSHugues Fruchet 		case 0:
3290c3f3ba3eSHugues Fruchet 			break;
3291c3f3ba3eSHugues Fruchet 		default:
3292c3f3ba3eSHugues Fruchet 			dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
3293c3f3ba3eSHugues Fruchet 				 rotation);
3294c3f3ba3eSHugues Fruchet 		}
3295c3f3ba3eSHugues Fruchet 	}
3296c3f3ba3eSHugues Fruchet 
3297ce96bcf5SSakari Ailus 	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
3298ce96bcf5SSakari Ailus 						  NULL);
329919a81c14SSteve Longerbeam 	if (!endpoint) {
330019a81c14SSteve Longerbeam 		dev_err(dev, "endpoint node not found\n");
330119a81c14SSteve Longerbeam 		return -EINVAL;
330219a81c14SSteve Longerbeam 	}
330319a81c14SSteve Longerbeam 
330419a81c14SSteve Longerbeam 	ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep);
330519a81c14SSteve Longerbeam 	fwnode_handle_put(endpoint);
330619a81c14SSteve Longerbeam 	if (ret) {
330719a81c14SSteve Longerbeam 		dev_err(dev, "Could not parse endpoint\n");
330819a81c14SSteve Longerbeam 		return ret;
330919a81c14SSteve Longerbeam 	}
331019a81c14SSteve Longerbeam 
33112c61e48dSLad Prabhakar 	if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
33122c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
33132c61e48dSLad Prabhakar 	    sensor->ep.bus_type != V4L2_MBUS_BT656) {
33142c61e48dSLad Prabhakar 		dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
33152c61e48dSLad Prabhakar 		return -EINVAL;
33162c61e48dSLad Prabhakar 	}
33172c61e48dSLad Prabhakar 
331819a81c14SSteve Longerbeam 	/* get system clock (xclk) */
331919a81c14SSteve Longerbeam 	sensor->xclk = devm_clk_get(dev, "xclk");
332019a81c14SSteve Longerbeam 	if (IS_ERR(sensor->xclk)) {
332119a81c14SSteve Longerbeam 		dev_err(dev, "failed to get xclk\n");
332219a81c14SSteve Longerbeam 		return PTR_ERR(sensor->xclk);
332319a81c14SSteve Longerbeam 	}
332419a81c14SSteve Longerbeam 
332519a81c14SSteve Longerbeam 	sensor->xclk_freq = clk_get_rate(sensor->xclk);
332619a81c14SSteve Longerbeam 	if (sensor->xclk_freq < OV5640_XCLK_MIN ||
332719a81c14SSteve Longerbeam 	    sensor->xclk_freq > OV5640_XCLK_MAX) {
332819a81c14SSteve Longerbeam 		dev_err(dev, "xclk frequency out of range: %d Hz\n",
332919a81c14SSteve Longerbeam 			sensor->xclk_freq);
333019a81c14SSteve Longerbeam 		return -EINVAL;
333119a81c14SSteve Longerbeam 	}
333219a81c14SSteve Longerbeam 
333319a81c14SSteve Longerbeam 	/* request optional power down pin */
333419a81c14SSteve Longerbeam 	sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown",
333519a81c14SSteve Longerbeam 						    GPIOD_OUT_HIGH);
33368791a102SFabio Estevam 	if (IS_ERR(sensor->pwdn_gpio))
33378791a102SFabio Estevam 		return PTR_ERR(sensor->pwdn_gpio);
33388791a102SFabio Estevam 
333919a81c14SSteve Longerbeam 	/* request optional reset pin */
334019a81c14SSteve Longerbeam 	sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
334119a81c14SSteve Longerbeam 						     GPIOD_OUT_HIGH);
33428791a102SFabio Estevam 	if (IS_ERR(sensor->reset_gpio))
33438791a102SFabio Estevam 		return PTR_ERR(sensor->reset_gpio);
334419a81c14SSteve Longerbeam 
334519a81c14SSteve Longerbeam 	v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
334619a81c14SSteve Longerbeam 
33472d18fbc5SAkinobu Mita 	sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
33482d18fbc5SAkinobu Mita 			    V4L2_SUBDEV_FL_HAS_EVENTS;
334919a81c14SSteve Longerbeam 	sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
335019a81c14SSteve Longerbeam 	sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
335119a81c14SSteve Longerbeam 	ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
335219a81c14SSteve Longerbeam 	if (ret)
335319a81c14SSteve Longerbeam 		return ret;
335419a81c14SSteve Longerbeam 
335519a81c14SSteve Longerbeam 	ret = ov5640_get_regulators(sensor);
335619a81c14SSteve Longerbeam 	if (ret)
335719a81c14SSteve Longerbeam 		return ret;
335819a81c14SSteve Longerbeam 
335919a81c14SSteve Longerbeam 	mutex_init(&sensor->lock);
336019a81c14SSteve Longerbeam 
33610f7acb52SHugues Fruchet 	ret = ov5640_check_chip_id(sensor);
33620f7acb52SHugues Fruchet 	if (ret)
33630f7acb52SHugues Fruchet 		goto entity_cleanup;
33640f7acb52SHugues Fruchet 
336519a81c14SSteve Longerbeam 	ret = ov5640_init_controls(sensor);
336619a81c14SSteve Longerbeam 	if (ret)
336719a81c14SSteve Longerbeam 		goto entity_cleanup;
336819a81c14SSteve Longerbeam 
336915786f7bSSakari Ailus 	ret = v4l2_async_register_subdev_sensor(&sensor->sd);
337019a81c14SSteve Longerbeam 	if (ret)
337119a81c14SSteve Longerbeam 		goto free_ctrls;
337219a81c14SSteve Longerbeam 
337319a81c14SSteve Longerbeam 	return 0;
337419a81c14SSteve Longerbeam 
337519a81c14SSteve Longerbeam free_ctrls:
337619a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
337719a81c14SSteve Longerbeam entity_cleanup:
337819a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
3379bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
338019a81c14SSteve Longerbeam 	return ret;
338119a81c14SSteve Longerbeam }
338219a81c14SSteve Longerbeam 
338319a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client)
338419a81c14SSteve Longerbeam {
338519a81c14SSteve Longerbeam 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
338619a81c14SSteve Longerbeam 	struct ov5640_dev *sensor = to_ov5640_dev(sd);
338719a81c14SSteve Longerbeam 
338819a81c14SSteve Longerbeam 	v4l2_async_unregister_subdev(&sensor->sd);
338919a81c14SSteve Longerbeam 	media_entity_cleanup(&sensor->sd.entity);
339019a81c14SSteve Longerbeam 	v4l2_ctrl_handler_free(&sensor->ctrls.handler);
3391bfcba38dSTomi Valkeinen 	mutex_destroy(&sensor->lock);
339219a81c14SSteve Longerbeam 
339319a81c14SSteve Longerbeam 	return 0;
339419a81c14SSteve Longerbeam }
339519a81c14SSteve Longerbeam 
339619a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = {
339719a81c14SSteve Longerbeam 	{"ov5640", 0},
339819a81c14SSteve Longerbeam 	{},
339919a81c14SSteve Longerbeam };
340019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id);
340119a81c14SSteve Longerbeam 
340219a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = {
340319a81c14SSteve Longerbeam 	{ .compatible = "ovti,ov5640" },
340419a81c14SSteve Longerbeam 	{ /* sentinel */ }
340519a81c14SSteve Longerbeam };
340619a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids);
340719a81c14SSteve Longerbeam 
340819a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = {
340919a81c14SSteve Longerbeam 	.driver = {
341019a81c14SSteve Longerbeam 		.name  = "ov5640",
341119a81c14SSteve Longerbeam 		.of_match_table	= ov5640_dt_ids,
341219a81c14SSteve Longerbeam 	},
341319a81c14SSteve Longerbeam 	.id_table = ov5640_id,
3414e6714993SKieran Bingham 	.probe_new = ov5640_probe,
341519a81c14SSteve Longerbeam 	.remove   = ov5640_remove,
341619a81c14SSteve Longerbeam };
341719a81c14SSteve Longerbeam 
341819a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver);
341919a81c14SSteve Longerbeam 
342019a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver");
342119a81c14SSteve Longerbeam MODULE_LICENSE("GPL");
3422