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 32*5113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH 2624 33*5113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT 1964 34*5113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP 14 35*5113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT 16 36*5113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH 2592 37*5113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT 1944 38*5113d5b3SJacopo Mondi 3919a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c 4019a81c14SSteve Longerbeam 413c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX 490000000U 423c28588fSJacopo Mondi 43d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02 0x3002 44d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 45f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0 0x3008 463b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 473b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 4819a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID 0x300a 49f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00 0x300e 50f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 51f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 5219a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00 0x3019 53f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1 0x302e 5419a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0 0x3034 5519a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1 0x3035 5619a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2 0x3036 5719a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3 0x3037 5819a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID 0x3100 59f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1 0x3103 6019a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER 0x3108 6119a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN 0x3400 6219a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN 0x3402 6319a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN 0x3404 6419a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL 0x3406 6519a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI 0x3500 6619a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED 0x3501 6719a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO 0x3502 6819a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL 0x3503 6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a 7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS 0x350c 713145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS 0x3800 723145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS 0x3802 733145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW 0x3804 743145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH 0x3806 7586633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO 0x3808 7686633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO 0x380a 7719a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS 0x380c 7819a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS 0x380e 793145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS 0x3810 803145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS 0x3812 81ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20 0x3820 8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21 0x3821 8319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00 0x3a00 8419a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP 0x3a08 8519a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP 0x3a0a 8619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D 0x3a0d 8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E 0x3a0e 8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F 0x3a0f 8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10 0x3a10 9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11 0x3a11 9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B 0x3a1b 9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E 0x3a1e 9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F 0x3a1f 9419a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00 0x3c00 9519a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01 0x3c01 9619a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c 9719a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01 0x4202 98e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00 0x4300 997cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE 0x4602 1007cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE 0x4604 1012b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT 0x4713 1024039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00 0x4730 103f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00 0x4740 10419a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00 0x4800 10519a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE 0x4814 1066c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD 0x4837 107e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f 10819a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1 0x503d 10919a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0 0x5580 11019a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1 0x5581 11119a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3 0x5583 11219a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4 0x5584 11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5 0x5585 11419a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT 0x56a1 11519a81c14SSteve Longerbeam 11619a81c14SSteve Longerbeam enum ov5640_mode_id { 11732ea5e05SHugues Fruchet OV5640_MODE_QQVGA_160_120 = 0, 11832ea5e05SHugues Fruchet OV5640_MODE_QCIF_176_144, 11919a81c14SSteve Longerbeam OV5640_MODE_QVGA_320_240, 12019a81c14SSteve Longerbeam OV5640_MODE_VGA_640_480, 12119a81c14SSteve Longerbeam OV5640_MODE_NTSC_720_480, 12219a81c14SSteve Longerbeam OV5640_MODE_PAL_720_576, 12319a81c14SSteve Longerbeam OV5640_MODE_XGA_1024_768, 12419a81c14SSteve Longerbeam OV5640_MODE_720P_1280_720, 12519a81c14SSteve Longerbeam OV5640_MODE_1080P_1920_1080, 12619a81c14SSteve Longerbeam OV5640_MODE_QSXGA_2592_1944, 12719a81c14SSteve Longerbeam OV5640_NUM_MODES, 12819a81c14SSteve Longerbeam }; 12919a81c14SSteve Longerbeam 13019a81c14SSteve Longerbeam enum ov5640_frame_rate { 13119a81c14SSteve Longerbeam OV5640_15_FPS = 0, 13219a81c14SSteve Longerbeam OV5640_30_FPS, 133e823fb16SMaxime Ripard OV5640_60_FPS, 13419a81c14SSteve Longerbeam OV5640_NUM_FRAMERATES, 13519a81c14SSteve Longerbeam }; 13619a81c14SSteve Longerbeam 13722845bf2SJacopo Mondi enum ov5640_pixel_rate_id { 13822845bf2SJacopo Mondi OV5640_PIXEL_RATE_168M, 13922845bf2SJacopo Mondi OV5640_PIXEL_RATE_148M, 14022845bf2SJacopo Mondi OV5640_PIXEL_RATE_124M, 14122845bf2SJacopo Mondi OV5640_PIXEL_RATE_96M, 14222845bf2SJacopo Mondi OV5640_PIXEL_RATE_48M, 14322845bf2SJacopo Mondi OV5640_NUM_PIXEL_RATES, 14422845bf2SJacopo Mondi }; 14522845bf2SJacopo Mondi 14622845bf2SJacopo Mondi /* 14722845bf2SJacopo Mondi * The chip manual suggests 24/48/96/192 MHz pixel clocks. 14822845bf2SJacopo Mondi * 14922845bf2SJacopo Mondi * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for 15022845bf2SJacopo Mondi * full resolution mode @15 FPS. 15122845bf2SJacopo Mondi */ 15222845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = { 15322845bf2SJacopo Mondi [OV5640_PIXEL_RATE_168M] = 168000000, 15422845bf2SJacopo Mondi [OV5640_PIXEL_RATE_148M] = 148000000, 15522845bf2SJacopo Mondi [OV5640_PIXEL_RATE_124M] = 124000000, 15622845bf2SJacopo Mondi [OV5640_PIXEL_RATE_96M] = 96000000, 15722845bf2SJacopo Mondi [OV5640_PIXEL_RATE_48M] = 48000000, 15822845bf2SJacopo Mondi }; 15922845bf2SJacopo Mondi 1607a3b8d4bSJacopo Mondi /* 1617a3b8d4bSJacopo Mondi * MIPI CSI-2 link frequencies. 1627a3b8d4bSJacopo Mondi * 1637a3b8d4bSJacopo Mondi * Derived from the above defined pixel rate for bpp = (8, 16, 24) and 1647a3b8d4bSJacopo Mondi * data_lanes = (1, 2) 1657a3b8d4bSJacopo Mondi * 1667a3b8d4bSJacopo Mondi * link_freq = (pixel_rate * bpp) / (2 * data_lanes) 1677a3b8d4bSJacopo Mondi */ 1687a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = { 1697a3b8d4bSJacopo Mondi 992000000, 888000000, 768000000, 744000000, 672000000, 672000000, 1707a3b8d4bSJacopo Mondi 592000000, 592000000, 576000000, 576000000, 496000000, 496000000, 1717a3b8d4bSJacopo Mondi 384000000, 384000000, 384000000, 336000000, 296000000, 288000000, 1727a3b8d4bSJacopo Mondi 248000000, 192000000, 192000000, 192000000, 96000000, 1737a3b8d4bSJacopo Mondi }; 1747a3b8d4bSJacopo Mondi 1757a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ 1767a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ 13 1777a3b8d4bSJacopo Mondi 178b7ed3abdSLoic Poulain enum ov5640_format_mux { 179b7ed3abdSLoic Poulain OV5640_FMT_MUX_YUV422 = 0, 180b7ed3abdSLoic Poulain OV5640_FMT_MUX_RGB, 181b7ed3abdSLoic Poulain OV5640_FMT_MUX_DITHER, 182b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_DPC, 183b7ed3abdSLoic Poulain OV5640_FMT_MUX_SNR_RAW, 184b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_CIP, 185b7ed3abdSLoic Poulain }; 186b7ed3abdSLoic Poulain 1872d7671f6SJacopo Mondi static const struct ov5640_pixfmt { 188e3ee691dSHugues Fruchet u32 code; 189e3ee691dSHugues Fruchet u32 colorspace; 1902d7671f6SJacopo Mondi u8 bpp; 1912d7671f6SJacopo Mondi } ov5640_formats[] = { 1922d7671f6SJacopo Mondi { 1932d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_JPEG_1X8, 1942d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_JPEG, 1952d7671f6SJacopo Mondi .bpp = 16, 1962d7671f6SJacopo Mondi }, { 1972d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_2X8, 1982d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 1992d7671f6SJacopo Mondi .bpp = 16, 2002d7671f6SJacopo Mondi }, { 2012d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_1X16, 2022d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2032d7671f6SJacopo Mondi .bpp = 16, 2042d7671f6SJacopo Mondi }, { 2052d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_2X8, 2062d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2072d7671f6SJacopo Mondi .bpp = 16, 2082d7671f6SJacopo Mondi }, { 2092d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_1X16, 2102d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2112d7671f6SJacopo Mondi .bpp = 16, 2122d7671f6SJacopo Mondi }, { 2132d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 2142d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2152d7671f6SJacopo Mondi .bpp = 16, 2162d7671f6SJacopo Mondi }, { 2172d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_BE, 2182d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2192d7671f6SJacopo Mondi .bpp = 16, 2202d7671f6SJacopo Mondi }, { 2212d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR8_1X8, 2222d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2232d7671f6SJacopo Mondi .bpp = 8, 2242d7671f6SJacopo Mondi }, { 2252d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGBRG8_1X8, 2262d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2272d7671f6SJacopo Mondi .bpp = 8 2282d7671f6SJacopo Mondi }, { 2292d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGRBG8_1X8, 2302d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2312d7671f6SJacopo Mondi .bpp = 8, 2322d7671f6SJacopo Mondi }, { 2332d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SRGGB8_1X8, 2342d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2352d7671f6SJacopo Mondi .bpp = 8, 2362d7671f6SJacopo Mondi }, 237e3ee691dSHugues Fruchet }; 238e3ee691dSHugues Fruchet 2393c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code) 2403c28588fSJacopo Mondi { 2413c28588fSJacopo Mondi unsigned int i; 2423c28588fSJacopo Mondi 2433c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) { 2443c28588fSJacopo Mondi if (ov5640_formats[i].code == code) 2453c28588fSJacopo Mondi return ov5640_formats[i].bpp; 2463c28588fSJacopo Mondi } 2473c28588fSJacopo Mondi 2483c28588fSJacopo Mondi return 0; 2493c28588fSJacopo Mondi } 2503c28588fSJacopo Mondi 25119a81c14SSteve Longerbeam /* 25219a81c14SSteve Longerbeam * FIXME: remove this when a subdev API becomes available 25319a81c14SSteve Longerbeam * to set the MIPI CSI-2 virtual channel. 25419a81c14SSteve Longerbeam */ 25519a81c14SSteve Longerbeam static unsigned int virtual_channel; 2568670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444); 25719a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel, 25819a81c14SSteve Longerbeam "MIPI CSI-2 virtual channel (0..3), default 0"); 25919a81c14SSteve Longerbeam 26019a81c14SSteve Longerbeam static const int ov5640_framerates[] = { 26119a81c14SSteve Longerbeam [OV5640_15_FPS] = 15, 26219a81c14SSteve Longerbeam [OV5640_30_FPS] = 30, 263e823fb16SMaxime Ripard [OV5640_60_FPS] = 60, 26419a81c14SSteve Longerbeam }; 26519a81c14SSteve Longerbeam 26619a81c14SSteve Longerbeam /* regulator supplies */ 26719a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = { 26841d8d7f5SHugues Fruchet "DOVDD", /* Digital I/O (1.8V) supply */ 26919a81c14SSteve Longerbeam "AVDD", /* Analog (2.8V) supply */ 27024c8ac89SFabio Estevam "DVDD", /* Digital Core (1.5V) supply */ 27119a81c14SSteve Longerbeam }; 27219a81c14SSteve Longerbeam 27319a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) 27419a81c14SSteve Longerbeam 27519a81c14SSteve Longerbeam /* 27619a81c14SSteve Longerbeam * Image size under 1280 * 960 are SUBSAMPLING 27719a81c14SSteve Longerbeam * Image size upper 1280 * 960 are SCALING 27819a81c14SSteve Longerbeam */ 27919a81c14SSteve Longerbeam enum ov5640_downsize_mode { 28019a81c14SSteve Longerbeam SUBSAMPLING, 28119a81c14SSteve Longerbeam SCALING, 28219a81c14SSteve Longerbeam }; 28319a81c14SSteve Longerbeam 28419a81c14SSteve Longerbeam struct reg_value { 28519a81c14SSteve Longerbeam u16 reg_addr; 28619a81c14SSteve Longerbeam u8 val; 28719a81c14SSteve Longerbeam u8 mask; 28819a81c14SSteve Longerbeam u32 delay_ms; 28919a81c14SSteve Longerbeam }; 29019a81c14SSteve Longerbeam 291*5113d5b3SJacopo Mondi struct ov5640_timings { 2923145efcdSJacopo Mondi /* Analog crop rectangle. */ 2933145efcdSJacopo Mondi struct v4l2_rect analog_crop; 2943145efcdSJacopo Mondi /* Visibile crop: from analog crop top-left corner. */ 2953145efcdSJacopo Mondi struct v4l2_rect crop; 296*5113d5b3SJacopo Mondi /* Total pixels per line: width + fixed hblank. */ 297476dec01SMaxime Ripard u32 htot; 298*5113d5b3SJacopo Mondi /* Default vertical blanking: frame height = height + vblank. */ 2993145efcdSJacopo Mondi u32 vblank_def; 300*5113d5b3SJacopo Mondi }; 301*5113d5b3SJacopo Mondi 302*5113d5b3SJacopo Mondi struct ov5640_mode_info { 303*5113d5b3SJacopo Mondi enum ov5640_mode_id id; 304*5113d5b3SJacopo Mondi enum ov5640_downsize_mode dn_mode; 305*5113d5b3SJacopo Mondi enum ov5640_pixel_rate_id pixel_rate; 306*5113d5b3SJacopo Mondi 307*5113d5b3SJacopo Mondi unsigned int width; 308*5113d5b3SJacopo Mondi unsigned int height; 309*5113d5b3SJacopo Mondi 310*5113d5b3SJacopo Mondi struct ov5640_timings dvp_timings; 311*5113d5b3SJacopo Mondi struct ov5640_timings csi2_timings; 312*5113d5b3SJacopo Mondi 31319a81c14SSteve Longerbeam const struct reg_value *reg_data; 31419a81c14SSteve Longerbeam u32 reg_data_size; 315*5113d5b3SJacopo Mondi 316*5113d5b3SJacopo Mondi /* Used by s_frame_interval only. */ 3175554c80eSAdam Ford u32 max_fps; 31819a81c14SSteve Longerbeam }; 31919a81c14SSteve Longerbeam 32019a81c14SSteve Longerbeam struct ov5640_ctrls { 32119a81c14SSteve Longerbeam struct v4l2_ctrl_handler handler; 322cc196e48SBenoit Parrot struct v4l2_ctrl *pixel_rate; 3237a3b8d4bSJacopo Mondi struct v4l2_ctrl *link_freq; 32419a81c14SSteve Longerbeam struct { 32519a81c14SSteve Longerbeam struct v4l2_ctrl *auto_exp; 32619a81c14SSteve Longerbeam struct v4l2_ctrl *exposure; 32719a81c14SSteve Longerbeam }; 32819a81c14SSteve Longerbeam struct { 32919a81c14SSteve Longerbeam struct v4l2_ctrl *auto_wb; 33019a81c14SSteve Longerbeam struct v4l2_ctrl *blue_balance; 33119a81c14SSteve Longerbeam struct v4l2_ctrl *red_balance; 33219a81c14SSteve Longerbeam }; 33319a81c14SSteve Longerbeam struct { 33419a81c14SSteve Longerbeam struct v4l2_ctrl *auto_gain; 33519a81c14SSteve Longerbeam struct v4l2_ctrl *gain; 33619a81c14SSteve Longerbeam }; 33719a81c14SSteve Longerbeam struct v4l2_ctrl *brightness; 3381068fecaSMylène Josserand struct v4l2_ctrl *light_freq; 33919a81c14SSteve Longerbeam struct v4l2_ctrl *saturation; 34019a81c14SSteve Longerbeam struct v4l2_ctrl *contrast; 34119a81c14SSteve Longerbeam struct v4l2_ctrl *hue; 34219a81c14SSteve Longerbeam struct v4l2_ctrl *test_pattern; 343ce85705aSHugues Fruchet struct v4l2_ctrl *hflip; 344ce85705aSHugues Fruchet struct v4l2_ctrl *vflip; 34519a81c14SSteve Longerbeam }; 34619a81c14SSteve Longerbeam 34719a81c14SSteve Longerbeam struct ov5640_dev { 34819a81c14SSteve Longerbeam struct i2c_client *i2c_client; 34919a81c14SSteve Longerbeam struct v4l2_subdev sd; 35019a81c14SSteve Longerbeam struct media_pad pad; 35119a81c14SSteve Longerbeam struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */ 35219a81c14SSteve Longerbeam struct clk *xclk; /* system clock to OV5640 */ 35319a81c14SSteve Longerbeam u32 xclk_freq; 35419a81c14SSteve Longerbeam 35519a81c14SSteve Longerbeam struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES]; 35619a81c14SSteve Longerbeam struct gpio_desc *reset_gpio; 35719a81c14SSteve Longerbeam struct gpio_desc *pwdn_gpio; 358c3f3ba3eSHugues Fruchet bool upside_down; 35919a81c14SSteve Longerbeam 36019a81c14SSteve Longerbeam /* lock to protect all members below */ 36119a81c14SSteve Longerbeam struct mutex lock; 36219a81c14SSteve Longerbeam 36319a81c14SSteve Longerbeam int power_count; 36419a81c14SSteve Longerbeam 36519a81c14SSteve Longerbeam struct v4l2_mbus_framefmt fmt; 366fb98e29fSHugues Fruchet bool pending_fmt_change; 36719a81c14SSteve Longerbeam 36819a81c14SSteve Longerbeam const struct ov5640_mode_info *current_mode; 369985cdcb0SHugues Fruchet const struct ov5640_mode_info *last_mode; 37019a81c14SSteve Longerbeam enum ov5640_frame_rate current_fr; 37119a81c14SSteve Longerbeam struct v4l2_fract frame_interval; 3723c28588fSJacopo Mondi s64 current_link_freq; 37319a81c14SSteve Longerbeam 37419a81c14SSteve Longerbeam struct ov5640_ctrls ctrls; 37519a81c14SSteve Longerbeam 37619a81c14SSteve Longerbeam u32 prev_sysclk, prev_hts; 37719a81c14SSteve Longerbeam u32 ae_low, ae_high, ae_target; 37819a81c14SSteve Longerbeam 37919a81c14SSteve Longerbeam bool pending_mode_change; 38019a81c14SSteve Longerbeam bool streaming; 38119a81c14SSteve Longerbeam }; 38219a81c14SSteve Longerbeam 38319a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd) 38419a81c14SSteve Longerbeam { 38519a81c14SSteve Longerbeam return container_of(sd, struct ov5640_dev, sd); 38619a81c14SSteve Longerbeam } 38719a81c14SSteve Longerbeam 38819a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) 38919a81c14SSteve Longerbeam { 39019a81c14SSteve Longerbeam return &container_of(ctrl->handler, struct ov5640_dev, 39119a81c14SSteve Longerbeam ctrls.handler)->sd; 39219a81c14SSteve Longerbeam } 39319a81c14SSteve Longerbeam 3948e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor) 3958e823f5cSJacopo Mondi { 3968e823f5cSJacopo Mondi return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY; 3978e823f5cSJacopo Mondi } 3988e823f5cSJacopo Mondi 39919a81c14SSteve Longerbeam /* 40019a81c14SSteve Longerbeam * FIXME: all of these register tables are likely filled with 40119a81c14SSteve Longerbeam * entries that set the register to their power-on default values, 40219a81c14SSteve Longerbeam * and which are otherwise not touched by this driver. Those entries 40319a81c14SSteve Longerbeam * should be identified and removed to speed register load time 40419a81c14SSteve Longerbeam * over i2c. 40519a81c14SSteve Longerbeam */ 406fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */ 40719a81c14SSteve Longerbeam static const struct reg_value ov5640_init_setting_30fps_VGA[] = { 40819a81c14SSteve Longerbeam {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, 409576f5d4bSLad Prabhakar {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, 41019a81c14SSteve Longerbeam {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, 41119a81c14SSteve Longerbeam {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, 41219a81c14SSteve Longerbeam {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, 41319a81c14SSteve Longerbeam {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, 41419a81c14SSteve Longerbeam {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, 41519a81c14SSteve Longerbeam {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, 41619a81c14SSteve Longerbeam {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, 41719a81c14SSteve Longerbeam {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, 41819a81c14SSteve Longerbeam {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, 41919a81c14SSteve Longerbeam {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, 42019a81c14SSteve Longerbeam {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, 42119a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 42219a81c14SSteve Longerbeam {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, 4233145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 42419a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 42519a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 42619a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 42719a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 42819a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 42919a81c14SSteve Longerbeam {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, 43019a81c14SSteve Longerbeam {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, 431aa4bb8b8SJacopo Mondi {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, 4322b5c18f9SChen-Yu Tsai {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, 43319a81c14SSteve Longerbeam {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 434aa4bb8b8SJacopo Mondi {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, 43519a81c14SSteve Longerbeam {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, 43619a81c14SSteve Longerbeam {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, 43719a81c14SSteve Longerbeam {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, 43819a81c14SSteve Longerbeam {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, 43919a81c14SSteve Longerbeam {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, 44019a81c14SSteve Longerbeam {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, 44119a81c14SSteve Longerbeam {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, 44219a81c14SSteve Longerbeam {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, 44319a81c14SSteve Longerbeam {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, 44419a81c14SSteve Longerbeam {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, 44519a81c14SSteve Longerbeam {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, 44619a81c14SSteve Longerbeam {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, 44719a81c14SSteve Longerbeam {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, 44819a81c14SSteve Longerbeam {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, 44919a81c14SSteve Longerbeam {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, 45019a81c14SSteve Longerbeam {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, 45119a81c14SSteve Longerbeam {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, 45219a81c14SSteve Longerbeam {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, 45319a81c14SSteve Longerbeam {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, 45419a81c14SSteve Longerbeam {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, 45519a81c14SSteve Longerbeam {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, 45619a81c14SSteve Longerbeam {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, 45719a81c14SSteve Longerbeam {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, 45819a81c14SSteve Longerbeam {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, 45919a81c14SSteve Longerbeam {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, 46019a81c14SSteve Longerbeam {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, 46119a81c14SSteve Longerbeam {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, 46219a81c14SSteve Longerbeam {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, 46319a81c14SSteve Longerbeam {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, 46419a81c14SSteve Longerbeam {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, 46519a81c14SSteve Longerbeam {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, 46619a81c14SSteve Longerbeam {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, 46719a81c14SSteve Longerbeam {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, 46819a81c14SSteve Longerbeam {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, 46919a81c14SSteve Longerbeam {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, 47019a81c14SSteve Longerbeam {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, 47119a81c14SSteve Longerbeam {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, 47219a81c14SSteve Longerbeam {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, 47319a81c14SSteve Longerbeam {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, 47419a81c14SSteve Longerbeam {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, 47519a81c14SSteve Longerbeam {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, 47619a81c14SSteve Longerbeam {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, 47719a81c14SSteve Longerbeam {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, 47819a81c14SSteve Longerbeam {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, 47919a81c14SSteve Longerbeam {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, 48019a81c14SSteve Longerbeam {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, 48119a81c14SSteve Longerbeam {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, 48219a81c14SSteve Longerbeam {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, 48319a81c14SSteve Longerbeam {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, 48419a81c14SSteve Longerbeam {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, 48519a81c14SSteve Longerbeam }; 48619a81c14SSteve Longerbeam 487086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_VGA_640_480[] = { 488c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 48919a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 490ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 4913145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 49219a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 49319a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 49419a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 49519a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 49619a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 4972b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 49819a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 49919a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 50019a81c14SSteve Longerbeam }; 50119a81c14SSteve Longerbeam 502086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_XGA_1024_768[] = { 503c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 50419a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 505ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5063145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 50719a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 50819a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 50919a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 51019a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 51119a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5122b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 51319a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 51486633417SMaxime Ripard {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 51519a81c14SSteve Longerbeam }; 51619a81c14SSteve Longerbeam 517086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QVGA_320_240[] = { 518c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 51919a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 520ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5213145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 52219a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 52319a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 52419a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 52519a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 52619a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5272b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 52819a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 52919a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 53019a81c14SSteve Longerbeam }; 53119a81c14SSteve Longerbeam 53232ea5e05SHugues Fruchet static const struct reg_value ov5640_setting_QQVGA_160_120[] = { 53332ea5e05SHugues Fruchet {0x3c07, 0x08, 0, 0}, 53432ea5e05SHugues Fruchet {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 53532ea5e05SHugues Fruchet {0x3814, 0x31, 0, 0}, 5363145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 53732ea5e05SHugues Fruchet {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 53832ea5e05SHugues Fruchet {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 53932ea5e05SHugues Fruchet {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 54032ea5e05SHugues Fruchet {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 54132ea5e05SHugues Fruchet {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 54232ea5e05SHugues Fruchet {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 54332ea5e05SHugues Fruchet {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, 54432ea5e05SHugues Fruchet }; 54532ea5e05SHugues Fruchet 546086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QCIF_176_144[] = { 547c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 54819a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 549ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5503145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 55119a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 55219a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 55319a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 55419a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 55519a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5562b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 55719a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 55819a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 55919a81c14SSteve Longerbeam }; 56019a81c14SSteve Longerbeam 561086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_NTSC_720_480[] = { 562c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 56319a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 564ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5653145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 56619a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 56719a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 56819a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 56919a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 57019a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5712b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 57219a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 57319a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 57419a81c14SSteve Longerbeam }; 57519a81c14SSteve Longerbeam 576086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_PAL_720_576[] = { 577c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 57819a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 579ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5803145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 58119a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 58219a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 58319a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 58419a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 58519a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5862b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 58719a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 58819a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, 58919a81c14SSteve Longerbeam }; 59019a81c14SSteve Longerbeam 591086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = { 592c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, 59319a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 594ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5953145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 59619a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 59719a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, 59819a81c14SSteve Longerbeam {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, 59919a81c14SSteve Longerbeam {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, 60019a81c14SSteve Longerbeam {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, 6012b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 60219a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, 60319a81c14SSteve Longerbeam {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, 60419a81c14SSteve Longerbeam }; 60519a81c14SSteve Longerbeam 606086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = { 607c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 60819a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 609ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 6103145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 61119a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 61219a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 61319a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 61419a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 61519a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 6162b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 61719a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 618c14d107eSMaxime Ripard {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, 619c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, 62019a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 621476dec01SMaxime Ripard {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, 62219a81c14SSteve Longerbeam {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, 62319a81c14SSteve Longerbeam {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, 62419a81c14SSteve Longerbeam {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, 6252b5c18f9SChen-Yu Tsai {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, 62619a81c14SSteve Longerbeam {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, 62792b9096cSBenoit Parrot {0x4005, 0x1a, 0, 0}, 62819a81c14SSteve Longerbeam }; 62919a81c14SSteve Longerbeam 630086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { 631c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 63219a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 633ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 6343145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 63519a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 63619a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 63719a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 63819a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 63919a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 6402b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 64119a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 64219a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, 64319a81c14SSteve Longerbeam }; 64419a81c14SSteve Longerbeam 64519a81c14SSteve Longerbeam /* power-on sensor init reg table */ 64619a81c14SSteve Longerbeam static const struct ov5640_mode_info ov5640_mode_init_data = { 6473145efcdSJacopo Mondi .id = 0, 6483145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6493145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 650*5113d5b3SJacopo Mondi .width = 640, 651*5113d5b3SJacopo Mondi .height = 480, 652*5113d5b3SJacopo Mondi .dvp_timings = { 6533145efcdSJacopo Mondi .analog_crop = { 6543145efcdSJacopo Mondi .left = 0, 6553145efcdSJacopo Mondi .top = 4, 6563145efcdSJacopo Mondi .width = 2624, 6573145efcdSJacopo Mondi .height = 1944, 6583145efcdSJacopo Mondi }, 6593145efcdSJacopo Mondi .crop = { 6603145efcdSJacopo Mondi .left = 16, 6613145efcdSJacopo Mondi .top = 6, 6623145efcdSJacopo Mondi .width = 640, 6633145efcdSJacopo Mondi .height = 480, 6643145efcdSJacopo Mondi }, 6653145efcdSJacopo Mondi .htot = 1896, 6663145efcdSJacopo Mondi .vblank_def = 504, 667*5113d5b3SJacopo Mondi }, 668*5113d5b3SJacopo Mondi .csi2_timings = { 669*5113d5b3SJacopo Mondi .analog_crop = { 670*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 671*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 672*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 673*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 674*5113d5b3SJacopo Mondi }, 675*5113d5b3SJacopo Mondi .crop = { 676*5113d5b3SJacopo Mondi .left = 2, 677*5113d5b3SJacopo Mondi .top = 4, 678*5113d5b3SJacopo Mondi .width = 640, 679*5113d5b3SJacopo Mondi .height = 480, 680*5113d5b3SJacopo Mondi }, 681*5113d5b3SJacopo Mondi .htot = 1896, 682*5113d5b3SJacopo Mondi .vblank_def = 504, 683*5113d5b3SJacopo Mondi }, 6843145efcdSJacopo Mondi .reg_data = ov5640_init_setting_30fps_VGA, 6853145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_init_setting_30fps_VGA), 6863145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 68719a81c14SSteve Longerbeam }; 68819a81c14SSteve Longerbeam 689*5113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = { 6908409d017SJacopo Mondi { 6918409d017SJacopo Mondi /* 160x120 */ 6923145efcdSJacopo Mondi .id = OV5640_MODE_QQVGA_160_120, 6933145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6943145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 695*5113d5b3SJacopo Mondi .width = 160, 696*5113d5b3SJacopo Mondi .height = 120, 697*5113d5b3SJacopo Mondi .dvp_timings = { 6983145efcdSJacopo Mondi .analog_crop = { 6993145efcdSJacopo Mondi .left = 0, 7003145efcdSJacopo Mondi .top = 4, 7013145efcdSJacopo Mondi .width = 2624, 7023145efcdSJacopo Mondi .height = 1944, 7033145efcdSJacopo Mondi }, 7043145efcdSJacopo Mondi .crop = { 7053145efcdSJacopo Mondi .left = 16, 7063145efcdSJacopo Mondi .top = 6, 7073145efcdSJacopo Mondi .width = 160, 7083145efcdSJacopo Mondi .height = 120, 7093145efcdSJacopo Mondi }, 7103145efcdSJacopo Mondi .htot = 1896, 7113145efcdSJacopo Mondi .vblank_def = 864, 712*5113d5b3SJacopo Mondi }, 713*5113d5b3SJacopo Mondi .csi2_timings = { 714*5113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 715*5113d5b3SJacopo Mondi .analog_crop = { 716*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 717*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 718*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 719*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 720*5113d5b3SJacopo Mondi }, 721*5113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 722*5113d5b3SJacopo Mondi .crop = { 723*5113d5b3SJacopo Mondi .left = 2, 724*5113d5b3SJacopo Mondi .top = 4, 725*5113d5b3SJacopo Mondi .width = 160, 726*5113d5b3SJacopo Mondi .height = 120, 727*5113d5b3SJacopo Mondi }, 728*5113d5b3SJacopo Mondi .htot = 1896, 729*5113d5b3SJacopo Mondi .vblank_def = 864, 730*5113d5b3SJacopo Mondi }, 7313145efcdSJacopo Mondi .reg_data = ov5640_setting_QQVGA_160_120, 7323145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QQVGA_160_120), 7333145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 7348409d017SJacopo Mondi }, { 7358409d017SJacopo Mondi /* 176x144 */ 7363145efcdSJacopo Mondi .id = OV5640_MODE_QCIF_176_144, 7373145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7383145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 739*5113d5b3SJacopo Mondi .width = 176, 740*5113d5b3SJacopo Mondi .height = 144, 741*5113d5b3SJacopo Mondi .dvp_timings = { 7423145efcdSJacopo Mondi .analog_crop = { 7433145efcdSJacopo Mondi .left = 0, 7443145efcdSJacopo Mondi .top = 4, 7453145efcdSJacopo Mondi .width = 2624, 7463145efcdSJacopo Mondi .height = 1944, 7473145efcdSJacopo Mondi }, 7483145efcdSJacopo Mondi .crop = { 7493145efcdSJacopo Mondi .left = 16, 7503145efcdSJacopo Mondi .top = 6, 7513145efcdSJacopo Mondi .width = 176, 7523145efcdSJacopo Mondi .height = 144, 7533145efcdSJacopo Mondi }, 7543145efcdSJacopo Mondi .htot = 1896, 7553145efcdSJacopo Mondi .vblank_def = 840, 756*5113d5b3SJacopo Mondi }, 757*5113d5b3SJacopo Mondi .csi2_timings = { 758*5113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 759*5113d5b3SJacopo Mondi .analog_crop = { 760*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 761*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 762*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 763*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 764*5113d5b3SJacopo Mondi }, 765*5113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 766*5113d5b3SJacopo Mondi .crop = { 767*5113d5b3SJacopo Mondi .left = 2, 768*5113d5b3SJacopo Mondi .top = 4, 769*5113d5b3SJacopo Mondi .width = 176, 770*5113d5b3SJacopo Mondi .height = 144, 771*5113d5b3SJacopo Mondi }, 772*5113d5b3SJacopo Mondi .htot = 1896, 773*5113d5b3SJacopo Mondi .vblank_def = 840, 774*5113d5b3SJacopo Mondi }, 7753145efcdSJacopo Mondi .reg_data = ov5640_setting_QCIF_176_144, 7763145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QCIF_176_144), 7773145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 7788409d017SJacopo Mondi }, { 7798409d017SJacopo Mondi /* 320x240 */ 7803145efcdSJacopo Mondi .id = OV5640_MODE_QVGA_320_240, 7813145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 782*5113d5b3SJacopo Mondi .width = 320, 783*5113d5b3SJacopo Mondi .height = 240, 7843145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 785*5113d5b3SJacopo Mondi .dvp_timings = { 7863145efcdSJacopo Mondi .analog_crop = { 7873145efcdSJacopo Mondi .left = 0, 7883145efcdSJacopo Mondi .top = 4, 7893145efcdSJacopo Mondi .width = 2624, 7903145efcdSJacopo Mondi .height = 1944, 7913145efcdSJacopo Mondi }, 7923145efcdSJacopo Mondi .crop = { 7933145efcdSJacopo Mondi .left = 16, 7943145efcdSJacopo Mondi .top = 6, 7953145efcdSJacopo Mondi .width = 320, 7963145efcdSJacopo Mondi .height = 240, 7973145efcdSJacopo Mondi }, 7983145efcdSJacopo Mondi .htot = 1896, 7993145efcdSJacopo Mondi .vblank_def = 744, 800*5113d5b3SJacopo Mondi }, 801*5113d5b3SJacopo Mondi .csi2_timings = { 802*5113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 803*5113d5b3SJacopo Mondi .analog_crop = { 804*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 805*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 806*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 807*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 808*5113d5b3SJacopo Mondi }, 809*5113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 810*5113d5b3SJacopo Mondi .crop = { 811*5113d5b3SJacopo Mondi .left = 2, 812*5113d5b3SJacopo Mondi .top = 4, 813*5113d5b3SJacopo Mondi .width = 320, 814*5113d5b3SJacopo Mondi .height = 240, 815*5113d5b3SJacopo Mondi }, 816*5113d5b3SJacopo Mondi .htot = 1896, 817*5113d5b3SJacopo Mondi .vblank_def = 744, 818*5113d5b3SJacopo Mondi }, 8193145efcdSJacopo Mondi .reg_data = ov5640_setting_QVGA_320_240, 8203145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QVGA_320_240), 8213145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 8228409d017SJacopo Mondi }, { 8238409d017SJacopo Mondi /* 640x480 */ 8243145efcdSJacopo Mondi .id = OV5640_MODE_VGA_640_480, 8253145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 8263145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 827*5113d5b3SJacopo Mondi .width = 640, 828*5113d5b3SJacopo Mondi .height = 480, 829*5113d5b3SJacopo Mondi .dvp_timings = { 8303145efcdSJacopo Mondi .analog_crop = { 8313145efcdSJacopo Mondi .left = 0, 8323145efcdSJacopo Mondi .top = 4, 8333145efcdSJacopo Mondi .width = 2624, 8343145efcdSJacopo Mondi .height = 1944, 8353145efcdSJacopo Mondi }, 8363145efcdSJacopo Mondi .crop = { 8373145efcdSJacopo Mondi .left = 16, 8383145efcdSJacopo Mondi .top = 6, 8393145efcdSJacopo Mondi .width = 640, 8403145efcdSJacopo Mondi .height = 480, 8413145efcdSJacopo Mondi }, 8423145efcdSJacopo Mondi .htot = 1896, 8433145efcdSJacopo Mondi .vblank_def = 600, 844*5113d5b3SJacopo Mondi }, 845*5113d5b3SJacopo Mondi .csi2_timings = { 846*5113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 847*5113d5b3SJacopo Mondi .analog_crop = { 848*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 849*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 850*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 851*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 852*5113d5b3SJacopo Mondi }, 853*5113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 854*5113d5b3SJacopo Mondi .crop = { 855*5113d5b3SJacopo Mondi .left = 2, 856*5113d5b3SJacopo Mondi .top = 4, 857*5113d5b3SJacopo Mondi .width = 640, 858*5113d5b3SJacopo Mondi .height = 480, 859*5113d5b3SJacopo Mondi }, 860*5113d5b3SJacopo Mondi .htot = 1896, 861*5113d5b3SJacopo Mondi .vblank_def = 600, 862*5113d5b3SJacopo Mondi }, 8633145efcdSJacopo Mondi .reg_data = ov5640_setting_VGA_640_480, 8643145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_VGA_640_480), 8653145efcdSJacopo Mondi .max_fps = OV5640_60_FPS 8668409d017SJacopo Mondi }, { 8678409d017SJacopo Mondi /* 720x480 */ 8683145efcdSJacopo Mondi .id = OV5640_MODE_NTSC_720_480, 8693145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 870*5113d5b3SJacopo Mondi .width = 720, 871*5113d5b3SJacopo Mondi .height = 480, 8723145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 873*5113d5b3SJacopo Mondi .dvp_timings = { 8743145efcdSJacopo Mondi .analog_crop = { 8753145efcdSJacopo Mondi .left = 0, 8763145efcdSJacopo Mondi .top = 4, 8773145efcdSJacopo Mondi .width = 2624, 8783145efcdSJacopo Mondi .height = 1944, 8793145efcdSJacopo Mondi }, 8803145efcdSJacopo Mondi .crop = { 881e74ef55bSJacopo Mondi .left = 56, 8823145efcdSJacopo Mondi .top = 60, 8833145efcdSJacopo Mondi .width = 720, 8843145efcdSJacopo Mondi .height = 480, 8853145efcdSJacopo Mondi }, 8863145efcdSJacopo Mondi .htot = 1896, 8873145efcdSJacopo Mondi .vblank_def = 504, 888*5113d5b3SJacopo Mondi }, 889*5113d5b3SJacopo Mondi .csi2_timings = { 890*5113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 891*5113d5b3SJacopo Mondi .analog_crop = { 892*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 893*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 894*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 895*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 896*5113d5b3SJacopo Mondi }, 897*5113d5b3SJacopo Mondi .crop = { 898*5113d5b3SJacopo Mondi .left = 56, 899*5113d5b3SJacopo Mondi .top = 60, 900*5113d5b3SJacopo Mondi .width = 720, 901*5113d5b3SJacopo Mondi .height = 480, 902*5113d5b3SJacopo Mondi }, 903*5113d5b3SJacopo Mondi .htot = 1896, 904*5113d5b3SJacopo Mondi .vblank_def = 504, 905*5113d5b3SJacopo Mondi }, 9063145efcdSJacopo Mondi .reg_data = ov5640_setting_NTSC_720_480, 9073145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_NTSC_720_480), 9083145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 9098409d017SJacopo Mondi }, { 9108409d017SJacopo Mondi /* 720x576 */ 9113145efcdSJacopo Mondi .id = OV5640_MODE_PAL_720_576, 9123145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 913*5113d5b3SJacopo Mondi .width = 720, 914*5113d5b3SJacopo Mondi .height = 576, 9153145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 916*5113d5b3SJacopo Mondi .dvp_timings = { 9173145efcdSJacopo Mondi .analog_crop = { 9183145efcdSJacopo Mondi .left = 0, 9193145efcdSJacopo Mondi .top = 4, 9203145efcdSJacopo Mondi .width = 2624, 9213145efcdSJacopo Mondi .height = 1944, 9223145efcdSJacopo Mondi }, 9233145efcdSJacopo Mondi .crop = { 9243145efcdSJacopo Mondi .left = 56, 9253145efcdSJacopo Mondi .top = 6, 9263145efcdSJacopo Mondi .width = 720, 9273145efcdSJacopo Mondi .height = 576, 9283145efcdSJacopo Mondi }, 9293145efcdSJacopo Mondi .htot = 1896, 9303145efcdSJacopo Mondi .vblank_def = 408, 931*5113d5b3SJacopo Mondi }, 932*5113d5b3SJacopo Mondi .csi2_timings = { 933*5113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 934*5113d5b3SJacopo Mondi .analog_crop = { 935*5113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 936*5113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 937*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 938*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 939*5113d5b3SJacopo Mondi }, 940*5113d5b3SJacopo Mondi .crop = { 941*5113d5b3SJacopo Mondi .left = 56, 942*5113d5b3SJacopo Mondi .top = 6, 943*5113d5b3SJacopo Mondi .width = 720, 944*5113d5b3SJacopo Mondi .height = 576, 945*5113d5b3SJacopo Mondi }, 946*5113d5b3SJacopo Mondi .htot = 1896, 947*5113d5b3SJacopo Mondi .vblank_def = 408, 948*5113d5b3SJacopo Mondi }, 9493145efcdSJacopo Mondi .reg_data = ov5640_setting_PAL_720_576, 9503145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_PAL_720_576), 9513145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 9528409d017SJacopo Mondi }, { 9538409d017SJacopo Mondi /* 1024x768 */ 9543145efcdSJacopo Mondi .id = OV5640_MODE_XGA_1024_768, 9553145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 9563145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 957*5113d5b3SJacopo Mondi .width = 1024, 958*5113d5b3SJacopo Mondi .height = 768, 959*5113d5b3SJacopo Mondi .dvp_timings = { 9603145efcdSJacopo Mondi .analog_crop = { 9613145efcdSJacopo Mondi .left = 0, 9623145efcdSJacopo Mondi .top = 4, 9633145efcdSJacopo Mondi .width = 2624, 9643145efcdSJacopo Mondi .height = 1944, 9653145efcdSJacopo Mondi }, 9663145efcdSJacopo Mondi .crop = { 9673145efcdSJacopo Mondi .left = 16, 9683145efcdSJacopo Mondi .top = 6, 9693145efcdSJacopo Mondi .width = 1024, 9703145efcdSJacopo Mondi .height = 768, 9713145efcdSJacopo Mondi }, 9723145efcdSJacopo Mondi .htot = 1896, 9733145efcdSJacopo Mondi .vblank_def = 312, 974*5113d5b3SJacopo Mondi }, 975*5113d5b3SJacopo Mondi .csi2_timings = { 976*5113d5b3SJacopo Mondi .analog_crop = { 977*5113d5b3SJacopo Mondi .left = 0, 978*5113d5b3SJacopo Mondi .top = 4, 979*5113d5b3SJacopo Mondi .width = OV5640_NATIVE_WIDTH, 980*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 981*5113d5b3SJacopo Mondi }, 982*5113d5b3SJacopo Mondi .crop = { 983*5113d5b3SJacopo Mondi .left = 16, 984*5113d5b3SJacopo Mondi .top = 6, 985*5113d5b3SJacopo Mondi .width = 1024, 986*5113d5b3SJacopo Mondi .height = 768, 987*5113d5b3SJacopo Mondi }, 988*5113d5b3SJacopo Mondi .htot = 1896, 989*5113d5b3SJacopo Mondi .vblank_def = 312, 990*5113d5b3SJacopo Mondi }, 9913145efcdSJacopo Mondi .reg_data = ov5640_setting_XGA_1024_768, 9923145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_XGA_1024_768), 9933145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 9948409d017SJacopo Mondi }, { 9958409d017SJacopo Mondi /* 1280x720 */ 9963145efcdSJacopo Mondi .id = OV5640_MODE_720P_1280_720, 9973145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 9983145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_124M, 999*5113d5b3SJacopo Mondi .width = 1280, 1000*5113d5b3SJacopo Mondi .height = 720, 1001*5113d5b3SJacopo Mondi .dvp_timings = { 10023145efcdSJacopo Mondi .analog_crop = { 10033145efcdSJacopo Mondi .left = 0, 10043145efcdSJacopo Mondi .top = 250, 10053145efcdSJacopo Mondi .width = 2624, 10063145efcdSJacopo Mondi .height = 1456, 10073145efcdSJacopo Mondi }, 10083145efcdSJacopo Mondi .crop = { 10093145efcdSJacopo Mondi .left = 16, 10103145efcdSJacopo Mondi .top = 4, 10113145efcdSJacopo Mondi .width = 1280, 10123145efcdSJacopo Mondi .height = 720, 10133145efcdSJacopo Mondi }, 10143145efcdSJacopo Mondi .htot = 1892, 10153145efcdSJacopo Mondi .vblank_def = 20, 1016*5113d5b3SJacopo Mondi }, 1017*5113d5b3SJacopo Mondi .csi2_timings = { 1018*5113d5b3SJacopo Mondi .analog_crop = { 1019*5113d5b3SJacopo Mondi .left = 0, 1020*5113d5b3SJacopo Mondi .top = 250, 1021*5113d5b3SJacopo Mondi .width = 2624, 1022*5113d5b3SJacopo Mondi .height = 1456, 1023*5113d5b3SJacopo Mondi }, 1024*5113d5b3SJacopo Mondi .crop = { 1025*5113d5b3SJacopo Mondi .left = 16, 1026*5113d5b3SJacopo Mondi .top = 4, 1027*5113d5b3SJacopo Mondi .width = 1280, 1028*5113d5b3SJacopo Mondi .height = 720, 1029*5113d5b3SJacopo Mondi }, 1030*5113d5b3SJacopo Mondi .htot = 1892, 1031*5113d5b3SJacopo Mondi .vblank_def = 20, 1032*5113d5b3SJacopo Mondi }, 10333145efcdSJacopo Mondi .reg_data = ov5640_setting_720P_1280_720, 10343145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720), 10353145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 10368409d017SJacopo Mondi }, { 10378409d017SJacopo Mondi /* 1920x1080 */ 10383145efcdSJacopo Mondi .id = OV5640_MODE_1080P_1920_1080, 10393145efcdSJacopo Mondi .dn_mode = SCALING, 10403145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_148M, 1041*5113d5b3SJacopo Mondi .width = 1920, 1042*5113d5b3SJacopo Mondi .height = 1080, 1043*5113d5b3SJacopo Mondi .dvp_timings = { 10443145efcdSJacopo Mondi .analog_crop = { 10453145efcdSJacopo Mondi .left = 336, 10463145efcdSJacopo Mondi .top = 434, 10473145efcdSJacopo Mondi .width = 1952, 10483145efcdSJacopo Mondi .height = 1088, 10493145efcdSJacopo Mondi }, 10503145efcdSJacopo Mondi .crop = { 10513145efcdSJacopo Mondi .left = 16, 10523145efcdSJacopo Mondi .top = 4, 10533145efcdSJacopo Mondi .width = 1920, 10543145efcdSJacopo Mondi .height = 1080, 10553145efcdSJacopo Mondi }, 10563145efcdSJacopo Mondi .htot = 2500, 10573145efcdSJacopo Mondi .vblank_def = 40, 1058*5113d5b3SJacopo Mondi }, 1059*5113d5b3SJacopo Mondi .csi2_timings = { 1060*5113d5b3SJacopo Mondi /* Crop the full valid pixel array in the center. */ 1061*5113d5b3SJacopo Mondi .analog_crop = { 1062*5113d5b3SJacopo Mondi .left = 336, 1063*5113d5b3SJacopo Mondi .top = 434, 1064*5113d5b3SJacopo Mondi .width = 1952, 1065*5113d5b3SJacopo Mondi .height = 1088, 1066*5113d5b3SJacopo Mondi }, 1067*5113d5b3SJacopo Mondi /* Maintain a larger processing margins. */ 1068*5113d5b3SJacopo Mondi .crop = { 1069*5113d5b3SJacopo Mondi .left = 16, 1070*5113d5b3SJacopo Mondi .top = 4, 1071*5113d5b3SJacopo Mondi .width = 1920, 1072*5113d5b3SJacopo Mondi .height = 1080, 1073*5113d5b3SJacopo Mondi }, 1074*5113d5b3SJacopo Mondi .htot = 2500, 1075*5113d5b3SJacopo Mondi .vblank_def = 40, 1076*5113d5b3SJacopo Mondi }, 10773145efcdSJacopo Mondi .reg_data = ov5640_setting_1080P_1920_1080, 10783145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080), 10793145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 10808409d017SJacopo Mondi }, { 10818409d017SJacopo Mondi /* 2592x1944 */ 10823145efcdSJacopo Mondi .id = OV5640_MODE_QSXGA_2592_1944, 10833145efcdSJacopo Mondi .dn_mode = SCALING, 10843145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_168M, 1085*5113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 1086*5113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 1087*5113d5b3SJacopo Mondi .dvp_timings = { 10883145efcdSJacopo Mondi .analog_crop = { 10893145efcdSJacopo Mondi .left = 0, 10903145efcdSJacopo Mondi .top = 0, 10913145efcdSJacopo Mondi .width = 2624, 10923145efcdSJacopo Mondi .height = 1952, 10933145efcdSJacopo Mondi }, 10943145efcdSJacopo Mondi .crop = { 10953145efcdSJacopo Mondi .left = 16, 10963145efcdSJacopo Mondi .top = 4, 10973145efcdSJacopo Mondi .width = 2592, 10983145efcdSJacopo Mondi .height = 1944, 10993145efcdSJacopo Mondi }, 11003145efcdSJacopo Mondi .htot = 2844, 11013145efcdSJacopo Mondi .vblank_def = 24, 1102*5113d5b3SJacopo Mondi }, 1103*5113d5b3SJacopo Mondi .csi2_timings = { 1104*5113d5b3SJacopo Mondi /* Give more processing margin to full resolution. */ 1105*5113d5b3SJacopo Mondi .analog_crop = { 1106*5113d5b3SJacopo Mondi .left = 0, 1107*5113d5b3SJacopo Mondi .top = 0, 1108*5113d5b3SJacopo Mondi .width = OV5640_NATIVE_WIDTH, 1109*5113d5b3SJacopo Mondi .height = 1952, 1110*5113d5b3SJacopo Mondi }, 1111*5113d5b3SJacopo Mondi .crop = { 1112*5113d5b3SJacopo Mondi .left = 16, 1113*5113d5b3SJacopo Mondi .top = 4, 1114*5113d5b3SJacopo Mondi .width = 2592, 1115*5113d5b3SJacopo Mondi .height = 1944, 1116*5113d5b3SJacopo Mondi }, 1117*5113d5b3SJacopo Mondi .htot = 2844, 1118*5113d5b3SJacopo Mondi .vblank_def = 24, 1119*5113d5b3SJacopo Mondi }, 11203145efcdSJacopo Mondi .reg_data = ov5640_setting_QSXGA_2592_1944, 11213145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), 11223145efcdSJacopo Mondi .max_fps = OV5640_15_FPS 11238409d017SJacopo Mondi }, 112419a81c14SSteve Longerbeam }; 112519a81c14SSteve Longerbeam 112619a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor) 112719a81c14SSteve Longerbeam { 112819a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 112919a81c14SSteve Longerbeam struct i2c_msg msg; 113019a81c14SSteve Longerbeam u8 buf[3]; 113119a81c14SSteve Longerbeam int ret; 113219a81c14SSteve Longerbeam 113319a81c14SSteve Longerbeam if (client->addr == OV5640_DEFAULT_SLAVE_ID) 113419a81c14SSteve Longerbeam return 0; 113519a81c14SSteve Longerbeam 113619a81c14SSteve Longerbeam buf[0] = OV5640_REG_SLAVE_ID >> 8; 113719a81c14SSteve Longerbeam buf[1] = OV5640_REG_SLAVE_ID & 0xff; 113819a81c14SSteve Longerbeam buf[2] = client->addr << 1; 113919a81c14SSteve Longerbeam 114019a81c14SSteve Longerbeam msg.addr = OV5640_DEFAULT_SLAVE_ID; 114119a81c14SSteve Longerbeam msg.flags = 0; 114219a81c14SSteve Longerbeam msg.buf = buf; 114319a81c14SSteve Longerbeam msg.len = sizeof(buf); 114419a81c14SSteve Longerbeam 114519a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 114619a81c14SSteve Longerbeam if (ret < 0) { 114719a81c14SSteve Longerbeam dev_err(&client->dev, "%s: failed with %d\n", __func__, ret); 114819a81c14SSteve Longerbeam return ret; 114919a81c14SSteve Longerbeam } 115019a81c14SSteve Longerbeam 115119a81c14SSteve Longerbeam return 0; 115219a81c14SSteve Longerbeam } 115319a81c14SSteve Longerbeam 115419a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) 115519a81c14SSteve Longerbeam { 115619a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 115719a81c14SSteve Longerbeam struct i2c_msg msg; 115819a81c14SSteve Longerbeam u8 buf[3]; 115919a81c14SSteve Longerbeam int ret; 116019a81c14SSteve Longerbeam 116119a81c14SSteve Longerbeam buf[0] = reg >> 8; 116219a81c14SSteve Longerbeam buf[1] = reg & 0xff; 116319a81c14SSteve Longerbeam buf[2] = val; 116419a81c14SSteve Longerbeam 116519a81c14SSteve Longerbeam msg.addr = client->addr; 116619a81c14SSteve Longerbeam msg.flags = client->flags; 116719a81c14SSteve Longerbeam msg.buf = buf; 116819a81c14SSteve Longerbeam msg.len = sizeof(buf); 116919a81c14SSteve Longerbeam 117019a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 117119a81c14SSteve Longerbeam if (ret < 0) { 11723924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", 117319a81c14SSteve Longerbeam __func__, reg, val); 117419a81c14SSteve Longerbeam return ret; 117519a81c14SSteve Longerbeam } 117619a81c14SSteve Longerbeam 117719a81c14SSteve Longerbeam return 0; 117819a81c14SSteve Longerbeam } 117919a81c14SSteve Longerbeam 118019a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) 118119a81c14SSteve Longerbeam { 118219a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 118319a81c14SSteve Longerbeam struct i2c_msg msg[2]; 118419a81c14SSteve Longerbeam u8 buf[2]; 118519a81c14SSteve Longerbeam int ret; 118619a81c14SSteve Longerbeam 118719a81c14SSteve Longerbeam buf[0] = reg >> 8; 118819a81c14SSteve Longerbeam buf[1] = reg & 0xff; 118919a81c14SSteve Longerbeam 119019a81c14SSteve Longerbeam msg[0].addr = client->addr; 119119a81c14SSteve Longerbeam msg[0].flags = client->flags; 119219a81c14SSteve Longerbeam msg[0].buf = buf; 119319a81c14SSteve Longerbeam msg[0].len = sizeof(buf); 119419a81c14SSteve Longerbeam 119519a81c14SSteve Longerbeam msg[1].addr = client->addr; 119619a81c14SSteve Longerbeam msg[1].flags = client->flags | I2C_M_RD; 119719a81c14SSteve Longerbeam msg[1].buf = buf; 119819a81c14SSteve Longerbeam msg[1].len = 1; 119919a81c14SSteve Longerbeam 120019a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, msg, 2); 12013924c623SHugues Fruchet if (ret < 0) { 12023924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x\n", 12033924c623SHugues Fruchet __func__, reg); 120419a81c14SSteve Longerbeam return ret; 12053924c623SHugues Fruchet } 120619a81c14SSteve Longerbeam 120719a81c14SSteve Longerbeam *val = buf[0]; 120819a81c14SSteve Longerbeam return 0; 120919a81c14SSteve Longerbeam } 121019a81c14SSteve Longerbeam 121119a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) 121219a81c14SSteve Longerbeam { 121319a81c14SSteve Longerbeam u8 hi, lo; 121419a81c14SSteve Longerbeam int ret; 121519a81c14SSteve Longerbeam 121619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &hi); 121719a81c14SSteve Longerbeam if (ret) 121819a81c14SSteve Longerbeam return ret; 121919a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg + 1, &lo); 122019a81c14SSteve Longerbeam if (ret) 122119a81c14SSteve Longerbeam return ret; 122219a81c14SSteve Longerbeam 122319a81c14SSteve Longerbeam *val = ((u16)hi << 8) | (u16)lo; 122419a81c14SSteve Longerbeam return 0; 122519a81c14SSteve Longerbeam } 122619a81c14SSteve Longerbeam 122719a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val) 122819a81c14SSteve Longerbeam { 122919a81c14SSteve Longerbeam int ret; 123019a81c14SSteve Longerbeam 123119a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg, val >> 8); 123219a81c14SSteve Longerbeam if (ret) 123319a81c14SSteve Longerbeam return ret; 123419a81c14SSteve Longerbeam 123519a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg + 1, val & 0xff); 123619a81c14SSteve Longerbeam } 123719a81c14SSteve Longerbeam 123819a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, 123919a81c14SSteve Longerbeam u8 mask, u8 val) 124019a81c14SSteve Longerbeam { 124119a81c14SSteve Longerbeam u8 readval; 124219a81c14SSteve Longerbeam int ret; 124319a81c14SSteve Longerbeam 124419a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &readval); 124519a81c14SSteve Longerbeam if (ret) 124619a81c14SSteve Longerbeam return ret; 124719a81c14SSteve Longerbeam 124819a81c14SSteve Longerbeam readval &= ~mask; 124919a81c14SSteve Longerbeam val &= mask; 125019a81c14SSteve Longerbeam val |= readval; 125119a81c14SSteve Longerbeam 125219a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg, val); 125319a81c14SSteve Longerbeam } 125419a81c14SSteve Longerbeam 1255aa288248SMaxime Ripard /* 1256aa288248SMaxime Ripard * After trying the various combinations, reading various 1257f8a7647dSMauro Carvalho Chehab * documentations spread around the net, and from the various 1258aa288248SMaxime Ripard * feedback, the clock tree is probably as follows: 1259aa288248SMaxime Ripard * 1260aa288248SMaxime Ripard * +--------------+ 1261aa288248SMaxime Ripard * | Ext. Clock | 1262aa288248SMaxime Ripard * +-+------------+ 1263aa288248SMaxime Ripard * | +----------+ 1264aa288248SMaxime Ripard * +->| PLL1 | - reg 0x3036, for the multiplier 1265aa288248SMaxime Ripard * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider 1266aa288248SMaxime Ripard * | +--------------+ 1267aa288248SMaxime Ripard * +->| System Clock | - reg 0x3035, bits 4-7 1268aa288248SMaxime Ripard * +-+------------+ 1269aa288248SMaxime Ripard * | +--------------+ 1270aa288248SMaxime Ripard * +->| MIPI Divider | - reg 0x3035, bits 0-3 1271aa288248SMaxime Ripard * | +-+------------+ 1272aa288248SMaxime Ripard * | +----------------> MIPI SCLK 1273aa288248SMaxime Ripard * | + +-----+ 1274aa288248SMaxime Ripard * | +->| / 2 |-------> MIPI BIT CLK 1275aa288248SMaxime Ripard * | +-----+ 1276aa288248SMaxime Ripard * | +--------------+ 1277aa288248SMaxime Ripard * +->| PLL Root Div | - reg 0x3037, bit 4 1278aa288248SMaxime Ripard * +-+------------+ 1279aa288248SMaxime Ripard * | +---------+ 12804c85f628SPaul Kocialkowski * +->| Bit Div | - reg 0x3034, bits 0-3 1281aa288248SMaxime Ripard * +-+-------+ 1282aa288248SMaxime Ripard * | +-------------+ 1283aa288248SMaxime Ripard * +->| SCLK Div | - reg 0x3108, bits 0-1 1284aa288248SMaxime Ripard * | +-+-----------+ 1285aa288248SMaxime Ripard * | +---------------> SCLK 1286aa288248SMaxime Ripard * | +-------------+ 1287aa288248SMaxime Ripard * +->| SCLK 2X Div | - reg 0x3108, bits 2-3 1288aa288248SMaxime Ripard * | +-+-----------+ 1289aa288248SMaxime Ripard * | +---------------> SCLK 2X 1290aa288248SMaxime Ripard * | +-------------+ 1291aa288248SMaxime Ripard * +->| PCLK Div | - reg 0x3108, bits 4-5 1292aa288248SMaxime Ripard * ++------------+ 1293aa288248SMaxime Ripard * + +-----------+ 1294aa288248SMaxime Ripard * +->| P_DIV | - reg 0x3035, bits 0-3 1295aa288248SMaxime Ripard * +-----+-----+ 1296aa288248SMaxime Ripard * +------------> PCLK 1297aa288248SMaxime Ripard * 12986c957ed7SJacopo Mondi * There seems to be also constraints: 1299aa288248SMaxime Ripard * - the PLL pre-divider output rate should be in the 4-27MHz range 1300aa288248SMaxime Ripard * - the PLL multiplier output rate should be in the 500-1000MHz range 1301aa288248SMaxime Ripard * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG 1302aa288248SMaxime Ripard */ 1303aa288248SMaxime Ripard 1304aa288248SMaxime Ripard /* 1305aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1306aa288248SMaxime Ripard * set to 3 in the vendor kernels. 1307aa288248SMaxime Ripard */ 1308aa288248SMaxime Ripard #define OV5640_PLL_PREDIV 3 1309aa288248SMaxime Ripard 1310aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN 4 1311aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX 252 1312aa288248SMaxime Ripard 1313aa288248SMaxime Ripard /* 1314aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 16, but the value is 1315aa288248SMaxime Ripard * always set to either 1 or 2 in the vendor kernels. 1316aa288248SMaxime Ripard */ 1317aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN 1 1318aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX 16 1319aa288248SMaxime Ripard 1320aa288248SMaxime Ripard /* 1321aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 2, but the value is always 1322aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1323aa288248SMaxime Ripard */ 1324aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV 2 1325aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4) 1326aa288248SMaxime Ripard 1327aa288248SMaxime Ripard /* 1328aa288248SMaxime Ripard * We only supports 8-bit formats at the moment 1329aa288248SMaxime Ripard */ 1330aa288248SMaxime Ripard #define OV5640_BIT_DIV 2 1331aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08 1332aa288248SMaxime Ripard 1333aa288248SMaxime Ripard /* 1334aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1335aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1336aa288248SMaxime Ripard */ 1337aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV 2 1338aa288248SMaxime Ripard 1339aa288248SMaxime Ripard /* 1340aa288248SMaxime Ripard * This is hardcoded so that the consistency is maintained between SCLK and 1341aa288248SMaxime Ripard * SCLK 2x. 1342aa288248SMaxime Ripard */ 1343aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2) 1344aa288248SMaxime Ripard 1345aa288248SMaxime Ripard /* 1346aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1347aa288248SMaxime Ripard * set to 1 in the vendor kernels. 1348aa288248SMaxime Ripard */ 1349aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV 1 1350aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00 1351aa288248SMaxime Ripard 1352aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor, 1353aa288248SMaxime Ripard u8 pll_prediv, u8 pll_mult, 1354aa288248SMaxime Ripard u8 sysdiv) 1355aa288248SMaxime Ripard { 1356aa288248SMaxime Ripard unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult; 1357aa288248SMaxime Ripard 1358aa288248SMaxime Ripard /* PLL1 output cannot exceed 1GHz. */ 1359aa288248SMaxime Ripard if (sysclk / 1000000 > 1000) 1360aa288248SMaxime Ripard return 0; 1361aa288248SMaxime Ripard 1362aa288248SMaxime Ripard return sysclk / sysdiv; 1363aa288248SMaxime Ripard } 1364aa288248SMaxime Ripard 1365aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor, 1366aa288248SMaxime Ripard unsigned long rate, 1367aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, 1368aa288248SMaxime Ripard u8 *sysdiv) 1369aa288248SMaxime Ripard { 1370aa288248SMaxime Ripard unsigned long best = ~0; 1371aa288248SMaxime Ripard u8 best_sysdiv = 1, best_mult = 1; 1372aa288248SMaxime Ripard u8 _sysdiv, _pll_mult; 1373aa288248SMaxime Ripard 1374aa288248SMaxime Ripard for (_sysdiv = OV5640_SYSDIV_MIN; 1375aa288248SMaxime Ripard _sysdiv <= OV5640_SYSDIV_MAX; 1376aa288248SMaxime Ripard _sysdiv++) { 1377aa288248SMaxime Ripard for (_pll_mult = OV5640_PLL_MULT_MIN; 1378aa288248SMaxime Ripard _pll_mult <= OV5640_PLL_MULT_MAX; 1379aa288248SMaxime Ripard _pll_mult++) { 1380aa288248SMaxime Ripard unsigned long _rate; 1381aa288248SMaxime Ripard 1382aa288248SMaxime Ripard /* 1383aa288248SMaxime Ripard * The PLL multiplier cannot be odd if above 1384aa288248SMaxime Ripard * 127. 1385aa288248SMaxime Ripard */ 1386aa288248SMaxime Ripard if (_pll_mult > 127 && (_pll_mult % 2)) 1387aa288248SMaxime Ripard continue; 1388aa288248SMaxime Ripard 1389aa288248SMaxime Ripard _rate = ov5640_compute_sys_clk(sensor, 1390aa288248SMaxime Ripard OV5640_PLL_PREDIV, 1391aa288248SMaxime Ripard _pll_mult, _sysdiv); 1392aa288248SMaxime Ripard 1393aa288248SMaxime Ripard /* 1394aa288248SMaxime Ripard * We have reached the maximum allowed PLL1 output, 1395aa288248SMaxime Ripard * increase sysdiv. 1396aa288248SMaxime Ripard */ 13972e3df204SAdam Ford if (!_rate) 1398aa288248SMaxime Ripard break; 1399aa288248SMaxime Ripard 1400aa288248SMaxime Ripard /* 1401aa288248SMaxime Ripard * Prefer rates above the expected clock rate than 1402aa288248SMaxime Ripard * below, even if that means being less precise. 1403aa288248SMaxime Ripard */ 1404aa288248SMaxime Ripard if (_rate < rate) 1405aa288248SMaxime Ripard continue; 1406aa288248SMaxime Ripard 1407aa288248SMaxime Ripard if (abs(rate - _rate) < abs(rate - best)) { 1408aa288248SMaxime Ripard best = _rate; 1409aa288248SMaxime Ripard best_sysdiv = _sysdiv; 1410aa288248SMaxime Ripard best_mult = _pll_mult; 1411aa288248SMaxime Ripard } 1412aa288248SMaxime Ripard 1413aa288248SMaxime Ripard if (_rate == rate) 1414aa288248SMaxime Ripard goto out; 1415aa288248SMaxime Ripard } 1416aa288248SMaxime Ripard } 1417aa288248SMaxime Ripard 1418aa288248SMaxime Ripard out: 1419aa288248SMaxime Ripard *sysdiv = best_sysdiv; 1420aa288248SMaxime Ripard *pll_prediv = OV5640_PLL_PREDIV; 1421aa288248SMaxime Ripard *pll_mult = best_mult; 1422aa288248SMaxime Ripard 1423aa288248SMaxime Ripard return best; 1424aa288248SMaxime Ripard } 1425aa288248SMaxime Ripard 1426aa288248SMaxime Ripard /* 1427aa288248SMaxime Ripard * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values 1428aa288248SMaxime Ripard * for the MIPI CSI-2 output. 1429aa288248SMaxime Ripard */ 14306c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) 1431aa288248SMaxime Ripard { 14326c957ed7SJacopo Mondi u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div; 1433aa288248SMaxime Ripard u8 prediv, mult, sysdiv; 14346c957ed7SJacopo Mondi unsigned long link_freq; 14356c957ed7SJacopo Mondi unsigned long sysclk; 14366c957ed7SJacopo Mondi u8 pclk_period; 14376c957ed7SJacopo Mondi u32 sample_rate; 14386c957ed7SJacopo Mondi u32 num_lanes; 1439aa288248SMaxime Ripard int ret; 1440aa288248SMaxime Ripard 14416c957ed7SJacopo Mondi /* Use the link freq computed at ov5640_update_pixel_rate() time. */ 14426c957ed7SJacopo Mondi link_freq = sensor->current_link_freq; 14436c957ed7SJacopo Mondi 1444aa288248SMaxime Ripard /* 14456c957ed7SJacopo Mondi * - mipi_div - Additional divider for the MIPI lane clock. 14466c957ed7SJacopo Mondi * 14476c957ed7SJacopo Mondi * Higher link frequencies would make sysclk > 1GHz. 14486c957ed7SJacopo Mondi * Keep the sysclk low and do not divide in the MIPI domain. 1449aa288248SMaxime Ripard */ 14506c957ed7SJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) 14516c957ed7SJacopo Mondi mipi_div = 1; 1452aa288248SMaxime Ripard else 14536c957ed7SJacopo Mondi mipi_div = 2; 1454aa288248SMaxime Ripard 14556c957ed7SJacopo Mondi sysclk = link_freq * mipi_div; 14566c957ed7SJacopo Mondi ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv); 1457aa288248SMaxime Ripard 14586c957ed7SJacopo Mondi /* 14596c957ed7SJacopo Mondi * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio. 14606c957ed7SJacopo Mondi * 14616c957ed7SJacopo Mondi * - root_div = 2 (fixed) 14626c957ed7SJacopo Mondi * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5 14636c957ed7SJacopo Mondi * - pclk_div = 1 (fixed) 14646c957ed7SJacopo Mondi * - p_div = (2 lanes ? mipi_div : 2 * mipi_div) 14656c957ed7SJacopo Mondi * 14666c957ed7SJacopo Mondi * This results in the following MIPI_SCLK depending on the number 14676c957ed7SJacopo Mondi * of lanes: 14686c957ed7SJacopo Mondi * 14696c957ed7SJacopo Mondi * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK 14706c957ed7SJacopo Mondi * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK 14716c957ed7SJacopo Mondi */ 14726c957ed7SJacopo Mondi root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2; 14736c957ed7SJacopo Mondi bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT; 14746c957ed7SJacopo Mondi pclk_div = ilog2(OV5640_PCLK_ROOT_DIV); 1475aa288248SMaxime Ripard 14766c957ed7SJacopo Mondi /* 14776c957ed7SJacopo Mondi * Scaler clock: 14786c957ed7SJacopo Mondi * - YUV: PCLK >= 2 * SCLK 14796c957ed7SJacopo Mondi * - RAW or JPEG: PCLK >= SCLK 14806c957ed7SJacopo Mondi * - sclk2x_div = sclk_div / 2 14816c957ed7SJacopo Mondi */ 14826c957ed7SJacopo Mondi sclk_div = ilog2(OV5640_SCLK_ROOT_DIV); 14836c957ed7SJacopo Mondi sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV); 14846c957ed7SJacopo Mondi 14856c957ed7SJacopo Mondi /* 14866c957ed7SJacopo Mondi * Set the pixel clock period expressed in ns with 1-bit decimal 14876c957ed7SJacopo Mondi * (0x01=0.5ns). 14886c957ed7SJacopo Mondi * 14896c957ed7SJacopo Mondi * The register is very briefly documented. In the OV5645 datasheet it 14906c957ed7SJacopo Mondi * is described as (2 * pclk period), and from testing it seems the 14916c957ed7SJacopo Mondi * actual definition is 2 * 8-bit sample period. 14926c957ed7SJacopo Mondi * 14936c957ed7SJacopo Mondi * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2 14946c957ed7SJacopo Mondi */ 14956c957ed7SJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 14966c957ed7SJacopo Mondi sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16; 14976c957ed7SJacopo Mondi pclk_period = 2000000000UL / sample_rate; 14986c957ed7SJacopo Mondi 14996c957ed7SJacopo Mondi /* Program the clock tree registers. */ 15006c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div); 15016c957ed7SJacopo Mondi if (ret) 15026c957ed7SJacopo Mondi return ret; 15036c957ed7SJacopo Mondi 15046c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff, 15056c957ed7SJacopo Mondi (sysdiv << 4) | mipi_div); 1506aa288248SMaxime Ripard if (ret) 1507aa288248SMaxime Ripard return ret; 1508aa288248SMaxime Ripard 1509aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult); 1510aa288248SMaxime Ripard if (ret) 1511aa288248SMaxime Ripard return ret; 1512aa288248SMaxime Ripard 15136c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f, 15146c957ed7SJacopo Mondi root_div | prediv); 1515aa288248SMaxime Ripard if (ret) 1516aa288248SMaxime Ripard return ret; 1517aa288248SMaxime Ripard 15186c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 15196c957ed7SJacopo Mondi (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); 15206c957ed7SJacopo Mondi if (ret) 15216c957ed7SJacopo Mondi return ret; 15226c957ed7SJacopo Mondi 15236c957ed7SJacopo Mondi return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period); 15246c957ed7SJacopo Mondi } 15256c957ed7SJacopo Mondi 15266c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) 15276c957ed7SJacopo Mondi { 15283145efcdSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 1529*5113d5b3SJacopo Mondi const struct ov5640_timings *timings = &mode->dvp_timings; 15306c957ed7SJacopo Mondi u32 rate; 15316c957ed7SJacopo Mondi 1532*5113d5b3SJacopo Mondi rate = timings->htot * (timings->crop.height + timings->vblank_def); 15336c957ed7SJacopo Mondi rate *= ov5640_framerates[sensor->current_fr]; 15346c957ed7SJacopo Mondi 15356c957ed7SJacopo Mondi return rate; 1536aa288248SMaxime Ripard } 1537aa288248SMaxime Ripard 1538aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, 1539aa288248SMaxime Ripard unsigned long rate, 1540aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, 1541aa288248SMaxime Ripard u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div) 1542aa288248SMaxime Ripard { 1543aa288248SMaxime Ripard unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV * 1544aa288248SMaxime Ripard OV5640_PCLK_ROOT_DIV; 1545aa288248SMaxime Ripard 1546aa288248SMaxime Ripard _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult, 1547aa288248SMaxime Ripard sysdiv); 1548aa288248SMaxime Ripard *pll_rdiv = OV5640_PLL_ROOT_DIV; 1549aa288248SMaxime Ripard *bit_div = OV5640_BIT_DIV; 1550aa288248SMaxime Ripard *pclk_div = OV5640_PCLK_ROOT_DIV; 1551aa288248SMaxime Ripard 1552aa288248SMaxime Ripard return _rate / *pll_rdiv / *bit_div / *pclk_div; 1553aa288248SMaxime Ripard } 1554aa288248SMaxime Ripard 15556c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) 1556aa288248SMaxime Ripard { 1557aa288248SMaxime Ripard u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; 15586c957ed7SJacopo Mondi u32 rate; 1559aa288248SMaxime Ripard int ret; 1560aa288248SMaxime Ripard 15616c957ed7SJacopo Mondi rate = ov5640_calc_pixel_rate(sensor); 15626c957ed7SJacopo Mondi rate *= ov5640_code_to_bpp(sensor->fmt.code); 15636c957ed7SJacopo Mondi rate /= sensor->ep.bus.parallel.bus_width; 15646c957ed7SJacopo Mondi 1565aa288248SMaxime Ripard ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, 1566aa288248SMaxime Ripard &bit_div, &pclk_div); 1567aa288248SMaxime Ripard 1568aa288248SMaxime Ripard if (bit_div == 2) 1569aa288248SMaxime Ripard bit_div = 8; 1570aa288248SMaxime Ripard 1571aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 1572aa288248SMaxime Ripard 0x0f, bit_div); 1573aa288248SMaxime Ripard if (ret) 1574aa288248SMaxime Ripard return ret; 1575aa288248SMaxime Ripard 1576aa288248SMaxime Ripard /* 1577aa288248SMaxime Ripard * We need to set sysdiv according to the clock, and to clear 1578aa288248SMaxime Ripard * the MIPI divider. 1579aa288248SMaxime Ripard */ 1580aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 1581aa288248SMaxime Ripard 0xff, sysdiv << 4); 1582aa288248SMaxime Ripard if (ret) 1583aa288248SMaxime Ripard return ret; 1584aa288248SMaxime Ripard 1585aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 1586aa288248SMaxime Ripard 0xff, mult); 1587aa288248SMaxime Ripard if (ret) 1588aa288248SMaxime Ripard return ret; 1589aa288248SMaxime Ripard 1590aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 1591aa288248SMaxime Ripard 0x1f, prediv | ((pll_rdiv - 1) << 4)); 1592aa288248SMaxime Ripard if (ret) 1593aa288248SMaxime Ripard return ret; 1594aa288248SMaxime Ripard 1595aa288248SMaxime Ripard return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30, 1596aa288248SMaxime Ripard (ilog2(pclk_div) << 4)); 1597aa288248SMaxime Ripard } 1598aa288248SMaxime Ripard 15997cb013b1SChen-Yu Tsai /* set JPEG framing sizes */ 16007cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, 16017cb013b1SChen-Yu Tsai const struct ov5640_mode_info *mode) 16027cb013b1SChen-Yu Tsai { 16037cb013b1SChen-Yu Tsai int ret; 16047cb013b1SChen-Yu Tsai 16052b5c18f9SChen-Yu Tsai /* 16062b5c18f9SChen-Yu Tsai * compression mode 3 timing 16072b5c18f9SChen-Yu Tsai * 16082b5c18f9SChen-Yu Tsai * Data is transmitted with programmable width (VFIFO_HSIZE). 16092b5c18f9SChen-Yu Tsai * No padding done. Last line may have less data. Varying 16102b5c18f9SChen-Yu Tsai * number of lines per frame, depending on amount of data. 16112b5c18f9SChen-Yu Tsai */ 16122b5c18f9SChen-Yu Tsai ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); 16132b5c18f9SChen-Yu Tsai if (ret < 0) 16142b5c18f9SChen-Yu Tsai return ret; 16152b5c18f9SChen-Yu Tsai 1616*5113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width); 16177cb013b1SChen-Yu Tsai if (ret < 0) 16187cb013b1SChen-Yu Tsai return ret; 16197cb013b1SChen-Yu Tsai 1620*5113d5b3SJacopo Mondi return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height); 16217cb013b1SChen-Yu Tsai } 16227cb013b1SChen-Yu Tsai 162319a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */ 1624bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor, 1625bad1774eSJacopo Mondi const struct ov5640_mode_info *mode) 1626bad1774eSJacopo Mondi { 1627*5113d5b3SJacopo Mondi const struct ov5640_timings *timings; 1628*5113d5b3SJacopo Mondi const struct v4l2_rect *analog_crop; 1629*5113d5b3SJacopo Mondi const struct v4l2_rect *crop; 1630bad1774eSJacopo Mondi int ret; 1631bad1774eSJacopo Mondi 16327cb013b1SChen-Yu Tsai if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { 16337cb013b1SChen-Yu Tsai ret = ov5640_set_jpeg_timings(sensor, mode); 16347cb013b1SChen-Yu Tsai if (ret < 0) 16357cb013b1SChen-Yu Tsai return ret; 16367cb013b1SChen-Yu Tsai } 16377cb013b1SChen-Yu Tsai 1638*5113d5b3SJacopo Mondi if (ov5640_is_csi2(sensor)) 1639*5113d5b3SJacopo Mondi timings = &mode->csi2_timings; 1640*5113d5b3SJacopo Mondi else 1641*5113d5b3SJacopo Mondi timings = &mode->dvp_timings; 1642*5113d5b3SJacopo Mondi 1643*5113d5b3SJacopo Mondi analog_crop = &timings->analog_crop; 1644*5113d5b3SJacopo Mondi crop = &timings->crop; 1645*5113d5b3SJacopo Mondi 16463145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS, 16473145efcdSJacopo Mondi analog_crop->left); 1648bad1774eSJacopo Mondi if (ret < 0) 1649bad1774eSJacopo Mondi return ret; 1650bad1774eSJacopo Mondi 16513145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS, 16523145efcdSJacopo Mondi analog_crop->top); 16533145efcdSJacopo Mondi if (ret < 0) 16543145efcdSJacopo Mondi return ret; 16553145efcdSJacopo Mondi 16563145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW, 16573145efcdSJacopo Mondi analog_crop->left + analog_crop->width - 1); 16583145efcdSJacopo Mondi if (ret < 0) 16593145efcdSJacopo Mondi return ret; 16603145efcdSJacopo Mondi 16613145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH, 16623145efcdSJacopo Mondi analog_crop->top + analog_crop->height - 1); 16633145efcdSJacopo Mondi if (ret < 0) 16643145efcdSJacopo Mondi return ret; 16653145efcdSJacopo Mondi 16663145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left); 16673145efcdSJacopo Mondi if (ret < 0) 16683145efcdSJacopo Mondi return ret; 16693145efcdSJacopo Mondi 16703145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top); 16713145efcdSJacopo Mondi if (ret < 0) 16723145efcdSJacopo Mondi return ret; 16733145efcdSJacopo Mondi 1674*5113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width); 16753145efcdSJacopo Mondi if (ret < 0) 16763145efcdSJacopo Mondi return ret; 16773145efcdSJacopo Mondi 1678*5113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height); 1679bad1774eSJacopo Mondi if (ret < 0) 1680bad1774eSJacopo Mondi return ret; 1681bad1774eSJacopo Mondi 1682*5113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot); 1683bad1774eSJacopo Mondi if (ret < 0) 1684bad1774eSJacopo Mondi return ret; 1685bad1774eSJacopo Mondi 16863145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, 1687*5113d5b3SJacopo Mondi mode->height + timings->vblank_def); 16883145efcdSJacopo Mondi if (ret < 0) 16893145efcdSJacopo Mondi return ret; 16903145efcdSJacopo Mondi 16913145efcdSJacopo Mondi return 0; 1692bad1774eSJacopo Mondi } 1693bad1774eSJacopo Mondi 169419a81c14SSteve Longerbeam static int ov5640_load_regs(struct ov5640_dev *sensor, 169519a81c14SSteve Longerbeam const struct ov5640_mode_info *mode) 169619a81c14SSteve Longerbeam { 169719a81c14SSteve Longerbeam const struct reg_value *regs = mode->reg_data; 169819a81c14SSteve Longerbeam unsigned int i; 169919a81c14SSteve Longerbeam u32 delay_ms; 170019a81c14SSteve Longerbeam u16 reg_addr; 170119a81c14SSteve Longerbeam u8 mask, val; 170219a81c14SSteve Longerbeam int ret = 0; 170319a81c14SSteve Longerbeam 170419a81c14SSteve Longerbeam for (i = 0; i < mode->reg_data_size; ++i, ++regs) { 170519a81c14SSteve Longerbeam delay_ms = regs->delay_ms; 170619a81c14SSteve Longerbeam reg_addr = regs->reg_addr; 170719a81c14SSteve Longerbeam val = regs->val; 170819a81c14SSteve Longerbeam mask = regs->mask; 170919a81c14SSteve Longerbeam 17103b987d70SLad Prabhakar /* remain in power down mode for DVP */ 17113b987d70SLad Prabhakar if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && 17123b987d70SLad Prabhakar val == OV5640_REG_SYS_CTRL0_SW_PWUP && 17138e823f5cSJacopo Mondi !ov5640_is_csi2(sensor)) 17143b987d70SLad Prabhakar continue; 17153b987d70SLad Prabhakar 171619a81c14SSteve Longerbeam if (mask) 171719a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, reg_addr, mask, val); 171819a81c14SSteve Longerbeam else 171919a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg_addr, val); 172019a81c14SSteve Longerbeam if (ret) 172119a81c14SSteve Longerbeam break; 172219a81c14SSteve Longerbeam 172319a81c14SSteve Longerbeam if (delay_ms) 172419a81c14SSteve Longerbeam usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); 172519a81c14SSteve Longerbeam } 172619a81c14SSteve Longerbeam 1727bad1774eSJacopo Mondi return ov5640_set_timings(sensor, mode); 172819a81c14SSteve Longerbeam } 172919a81c14SSteve Longerbeam 1730dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) 1731dc29a1c1SHugues Fruchet { 1732dc29a1c1SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 1733dc29a1c1SHugues Fruchet BIT(0), on ? 0 : BIT(0)); 1734dc29a1c1SHugues Fruchet } 1735dc29a1c1SHugues Fruchet 173619a81c14SSteve Longerbeam /* read exposure, in number of line periods */ 173719a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor) 173819a81c14SSteve Longerbeam { 173919a81c14SSteve Longerbeam int exp, ret; 174019a81c14SSteve Longerbeam u8 temp; 174119a81c14SSteve Longerbeam 174219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp); 174319a81c14SSteve Longerbeam if (ret) 174419a81c14SSteve Longerbeam return ret; 174519a81c14SSteve Longerbeam exp = ((int)temp & 0x0f) << 16; 174619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp); 174719a81c14SSteve Longerbeam if (ret) 174819a81c14SSteve Longerbeam return ret; 174919a81c14SSteve Longerbeam exp |= ((int)temp << 8); 175019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp); 175119a81c14SSteve Longerbeam if (ret) 175219a81c14SSteve Longerbeam return ret; 175319a81c14SSteve Longerbeam exp |= (int)temp; 175419a81c14SSteve Longerbeam 175519a81c14SSteve Longerbeam return exp >> 4; 175619a81c14SSteve Longerbeam } 175719a81c14SSteve Longerbeam 175819a81c14SSteve Longerbeam /* write exposure, given number of line periods */ 175919a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure) 176019a81c14SSteve Longerbeam { 176119a81c14SSteve Longerbeam int ret; 176219a81c14SSteve Longerbeam 176319a81c14SSteve Longerbeam exposure <<= 4; 176419a81c14SSteve Longerbeam 176519a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 176619a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_LO, 176719a81c14SSteve Longerbeam exposure & 0xff); 176819a81c14SSteve Longerbeam if (ret) 176919a81c14SSteve Longerbeam return ret; 177019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 177119a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_MED, 177219a81c14SSteve Longerbeam (exposure >> 8) & 0xff); 177319a81c14SSteve Longerbeam if (ret) 177419a81c14SSteve Longerbeam return ret; 177519a81c14SSteve Longerbeam return ov5640_write_reg(sensor, 177619a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_HI, 177719a81c14SSteve Longerbeam (exposure >> 16) & 0x0f); 177819a81c14SSteve Longerbeam } 177919a81c14SSteve Longerbeam 178019a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor) 178119a81c14SSteve Longerbeam { 178219a81c14SSteve Longerbeam u16 gain; 178319a81c14SSteve Longerbeam int ret; 178419a81c14SSteve Longerbeam 178519a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain); 178619a81c14SSteve Longerbeam if (ret) 178719a81c14SSteve Longerbeam return ret; 178819a81c14SSteve Longerbeam 178919a81c14SSteve Longerbeam return gain & 0x3ff; 179019a81c14SSteve Longerbeam } 179119a81c14SSteve Longerbeam 17923cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain) 17933cca8ef5SHugues Fruchet { 17943cca8ef5SHugues Fruchet return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, 17953cca8ef5SHugues Fruchet (u16)gain & 0x3ff); 17963cca8ef5SHugues Fruchet } 17973cca8ef5SHugues Fruchet 17983cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) 17993cca8ef5SHugues Fruchet { 18003cca8ef5SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 18013cca8ef5SHugues Fruchet BIT(1), on ? 0 : BIT(1)); 18023cca8ef5SHugues Fruchet } 18033cca8ef5SHugues Fruchet 1804f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) 1805f22996dbSHugues Fruchet { 18063b987d70SLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? 18073b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWUP : 18083b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWDN); 1809f22996dbSHugues Fruchet } 1810f22996dbSHugues Fruchet 1811f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) 181219a81c14SSteve Longerbeam { 181319a81c14SSteve Longerbeam int ret; 181419a81c14SSteve Longerbeam 1815aa4bb8b8SJacopo Mondi /* 1816aa4bb8b8SJacopo Mondi * Enable/disable the MIPI interface 1817aa4bb8b8SJacopo Mondi * 1818aa4bb8b8SJacopo Mondi * 0x300e = on ? 0x45 : 0x40 1819aa4bb8b8SJacopo Mondi * 1820aa4bb8b8SJacopo Mondi * FIXME: the sensor manual (version 2.03) reports 1821aa4bb8b8SJacopo Mondi * [7:5] = 000 : 1 data lane mode 1822aa4bb8b8SJacopo Mondi * [7:5] = 001 : 2 data lanes mode 1823aa4bb8b8SJacopo Mondi * But this settings do not work, while the following ones 1824aa4bb8b8SJacopo Mondi * have been validated for 2 data lanes mode. 1825aa4bb8b8SJacopo Mondi * 1826aa4bb8b8SJacopo Mondi * [7:5] = 010 : 2 data lanes mode 1827aa4bb8b8SJacopo Mondi * [4] = 0 : Power up MIPI HS Tx 1828aa4bb8b8SJacopo Mondi * [3] = 0 : Power up MIPI LS Rx 1829aa4bb8b8SJacopo Mondi * [2] = 1/0 : MIPI interface enable/disable 1830aa4bb8b8SJacopo Mondi * [1:0] = 01/00: FIXME: 'debug' 1831aa4bb8b8SJacopo Mondi */ 1832aa4bb8b8SJacopo Mondi ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 1833aa4bb8b8SJacopo Mondi on ? 0x45 : 0x40); 183419a81c14SSteve Longerbeam if (ret) 183519a81c14SSteve Longerbeam return ret; 183619a81c14SSteve Longerbeam 183719a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01, 183819a81c14SSteve Longerbeam on ? 0x00 : 0x0f); 183919a81c14SSteve Longerbeam } 184019a81c14SSteve Longerbeam 184119a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor) 184219a81c14SSteve Longerbeam { 184319a81c14SSteve Longerbeam /* calculate sysclk */ 184419a81c14SSteve Longerbeam u32 xvclk = sensor->xclk_freq / 10000; 184519a81c14SSteve Longerbeam u32 multiplier, prediv, VCO, sysdiv, pll_rdiv; 184619a81c14SSteve Longerbeam u32 sclk_rdiv_map[] = {1, 2, 4, 8}; 184719a81c14SSteve Longerbeam u32 bit_div2x = 1, sclk_rdiv, sysclk; 184819a81c14SSteve Longerbeam u8 temp1, temp2; 184919a81c14SSteve Longerbeam int ret; 185019a81c14SSteve Longerbeam 185119a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1); 185219a81c14SSteve Longerbeam if (ret) 185319a81c14SSteve Longerbeam return ret; 185419a81c14SSteve Longerbeam temp2 = temp1 & 0x0f; 185519a81c14SSteve Longerbeam if (temp2 == 8 || temp2 == 10) 185619a81c14SSteve Longerbeam bit_div2x = temp2 / 2; 185719a81c14SSteve Longerbeam 185819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1); 185919a81c14SSteve Longerbeam if (ret) 186019a81c14SSteve Longerbeam return ret; 186119a81c14SSteve Longerbeam sysdiv = temp1 >> 4; 186219a81c14SSteve Longerbeam if (sysdiv == 0) 186319a81c14SSteve Longerbeam sysdiv = 16; 186419a81c14SSteve Longerbeam 186519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1); 186619a81c14SSteve Longerbeam if (ret) 186719a81c14SSteve Longerbeam return ret; 186819a81c14SSteve Longerbeam multiplier = temp1; 186919a81c14SSteve Longerbeam 187019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1); 187119a81c14SSteve Longerbeam if (ret) 187219a81c14SSteve Longerbeam return ret; 187319a81c14SSteve Longerbeam prediv = temp1 & 0x0f; 187419a81c14SSteve Longerbeam pll_rdiv = ((temp1 >> 4) & 0x01) + 1; 187519a81c14SSteve Longerbeam 187619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1); 187719a81c14SSteve Longerbeam if (ret) 187819a81c14SSteve Longerbeam return ret; 187919a81c14SSteve Longerbeam temp2 = temp1 & 0x03; 188019a81c14SSteve Longerbeam sclk_rdiv = sclk_rdiv_map[temp2]; 188119a81c14SSteve Longerbeam 188219a81c14SSteve Longerbeam if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x) 188319a81c14SSteve Longerbeam return -EINVAL; 188419a81c14SSteve Longerbeam 188519a81c14SSteve Longerbeam VCO = xvclk * multiplier / prediv; 188619a81c14SSteve Longerbeam 188719a81c14SSteve Longerbeam sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv; 188819a81c14SSteve Longerbeam 188919a81c14SSteve Longerbeam return sysclk; 189019a81c14SSteve Longerbeam } 189119a81c14SSteve Longerbeam 189219a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor) 189319a81c14SSteve Longerbeam { 189419a81c14SSteve Longerbeam /* read HTS from register settings */ 189519a81c14SSteve Longerbeam u8 mode; 189619a81c14SSteve Longerbeam int ret; 189719a81c14SSteve Longerbeam 189819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode); 189919a81c14SSteve Longerbeam if (ret) 190019a81c14SSteve Longerbeam return ret; 190119a81c14SSteve Longerbeam mode &= 0xfb; 190219a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode); 190319a81c14SSteve Longerbeam } 190419a81c14SSteve Longerbeam 190519a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor) 190619a81c14SSteve Longerbeam { 190719a81c14SSteve Longerbeam /* read HTS from register settings */ 190819a81c14SSteve Longerbeam u16 hts; 190919a81c14SSteve Longerbeam int ret; 191019a81c14SSteve Longerbeam 191119a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts); 191219a81c14SSteve Longerbeam if (ret) 191319a81c14SSteve Longerbeam return ret; 191419a81c14SSteve Longerbeam return hts; 191519a81c14SSteve Longerbeam } 191619a81c14SSteve Longerbeam 191719a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor) 191819a81c14SSteve Longerbeam { 191919a81c14SSteve Longerbeam u16 vts; 192019a81c14SSteve Longerbeam int ret; 192119a81c14SSteve Longerbeam 192219a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts); 192319a81c14SSteve Longerbeam if (ret) 192419a81c14SSteve Longerbeam return ret; 192519a81c14SSteve Longerbeam return vts; 192619a81c14SSteve Longerbeam } 192719a81c14SSteve Longerbeam 192819a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts) 192919a81c14SSteve Longerbeam { 193019a81c14SSteve Longerbeam return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts); 193119a81c14SSteve Longerbeam } 193219a81c14SSteve Longerbeam 193319a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor) 193419a81c14SSteve Longerbeam { 193519a81c14SSteve Longerbeam /* get banding filter value */ 193619a81c14SSteve Longerbeam int ret, light_freq = 0; 193719a81c14SSteve Longerbeam u8 temp, temp1; 193819a81c14SSteve Longerbeam 193919a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp); 194019a81c14SSteve Longerbeam if (ret) 194119a81c14SSteve Longerbeam return ret; 194219a81c14SSteve Longerbeam 194319a81c14SSteve Longerbeam if (temp & 0x80) { 194419a81c14SSteve Longerbeam /* manual */ 194519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00, 194619a81c14SSteve Longerbeam &temp1); 194719a81c14SSteve Longerbeam if (ret) 194819a81c14SSteve Longerbeam return ret; 194919a81c14SSteve Longerbeam if (temp1 & 0x04) { 195019a81c14SSteve Longerbeam /* 50Hz */ 195119a81c14SSteve Longerbeam light_freq = 50; 195219a81c14SSteve Longerbeam } else { 195319a81c14SSteve Longerbeam /* 60Hz */ 195419a81c14SSteve Longerbeam light_freq = 60; 195519a81c14SSteve Longerbeam } 195619a81c14SSteve Longerbeam } else { 195719a81c14SSteve Longerbeam /* auto */ 195819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C, 195919a81c14SSteve Longerbeam &temp1); 196019a81c14SSteve Longerbeam if (ret) 196119a81c14SSteve Longerbeam return ret; 196219a81c14SSteve Longerbeam 196319a81c14SSteve Longerbeam if (temp1 & 0x01) { 196419a81c14SSteve Longerbeam /* 50Hz */ 196519a81c14SSteve Longerbeam light_freq = 50; 196619a81c14SSteve Longerbeam } else { 196719a81c14SSteve Longerbeam /* 60Hz */ 196819a81c14SSteve Longerbeam } 196919a81c14SSteve Longerbeam } 197019a81c14SSteve Longerbeam 197119a81c14SSteve Longerbeam return light_freq; 197219a81c14SSteve Longerbeam } 197319a81c14SSteve Longerbeam 197419a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor) 197519a81c14SSteve Longerbeam { 197619a81c14SSteve Longerbeam u32 band_step60, max_band60, band_step50, max_band50, prev_vts; 197719a81c14SSteve Longerbeam int ret; 197819a81c14SSteve Longerbeam 197919a81c14SSteve Longerbeam /* read preview PCLK */ 198019a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 198119a81c14SSteve Longerbeam if (ret < 0) 198219a81c14SSteve Longerbeam return ret; 198319a81c14SSteve Longerbeam if (ret == 0) 198419a81c14SSteve Longerbeam return -EINVAL; 198519a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 198619a81c14SSteve Longerbeam /* read preview HTS */ 198719a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 198819a81c14SSteve Longerbeam if (ret < 0) 198919a81c14SSteve Longerbeam return ret; 199019a81c14SSteve Longerbeam if (ret == 0) 199119a81c14SSteve Longerbeam return -EINVAL; 199219a81c14SSteve Longerbeam sensor->prev_hts = ret; 199319a81c14SSteve Longerbeam 199419a81c14SSteve Longerbeam /* read preview VTS */ 199519a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 199619a81c14SSteve Longerbeam if (ret < 0) 199719a81c14SSteve Longerbeam return ret; 199819a81c14SSteve Longerbeam prev_vts = ret; 199919a81c14SSteve Longerbeam 200019a81c14SSteve Longerbeam /* calculate banding filter */ 200119a81c14SSteve Longerbeam /* 60Hz */ 200219a81c14SSteve Longerbeam band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; 200319a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60); 200419a81c14SSteve Longerbeam if (ret) 200519a81c14SSteve Longerbeam return ret; 200619a81c14SSteve Longerbeam if (!band_step60) 200719a81c14SSteve Longerbeam return -EINVAL; 200819a81c14SSteve Longerbeam max_band60 = (int)((prev_vts - 4) / band_step60); 200919a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60); 201019a81c14SSteve Longerbeam if (ret) 201119a81c14SSteve Longerbeam return ret; 201219a81c14SSteve Longerbeam 201319a81c14SSteve Longerbeam /* 50Hz */ 201419a81c14SSteve Longerbeam band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts; 201519a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50); 201619a81c14SSteve Longerbeam if (ret) 201719a81c14SSteve Longerbeam return ret; 201819a81c14SSteve Longerbeam if (!band_step50) 201919a81c14SSteve Longerbeam return -EINVAL; 202019a81c14SSteve Longerbeam max_band50 = (int)((prev_vts - 4) / band_step50); 202119a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50); 202219a81c14SSteve Longerbeam } 202319a81c14SSteve Longerbeam 202419a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target) 202519a81c14SSteve Longerbeam { 202619a81c14SSteve Longerbeam /* stable in high */ 202719a81c14SSteve Longerbeam u32 fast_high, fast_low; 202819a81c14SSteve Longerbeam int ret; 202919a81c14SSteve Longerbeam 203019a81c14SSteve Longerbeam sensor->ae_low = target * 23 / 25; /* 0.92 */ 203119a81c14SSteve Longerbeam sensor->ae_high = target * 27 / 25; /* 1.08 */ 203219a81c14SSteve Longerbeam 203319a81c14SSteve Longerbeam fast_high = sensor->ae_high << 1; 203419a81c14SSteve Longerbeam if (fast_high > 255) 203519a81c14SSteve Longerbeam fast_high = 255; 203619a81c14SSteve Longerbeam 203719a81c14SSteve Longerbeam fast_low = sensor->ae_low >> 1; 203819a81c14SSteve Longerbeam 203919a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high); 204019a81c14SSteve Longerbeam if (ret) 204119a81c14SSteve Longerbeam return ret; 204219a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low); 204319a81c14SSteve Longerbeam if (ret) 204419a81c14SSteve Longerbeam return ret; 204519a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high); 204619a81c14SSteve Longerbeam if (ret) 204719a81c14SSteve Longerbeam return ret; 204819a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low); 204919a81c14SSteve Longerbeam if (ret) 205019a81c14SSteve Longerbeam return ret; 205119a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high); 205219a81c14SSteve Longerbeam if (ret) 205319a81c14SSteve Longerbeam return ret; 205419a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low); 205519a81c14SSteve Longerbeam } 205619a81c14SSteve Longerbeam 2057c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor) 205819a81c14SSteve Longerbeam { 205919a81c14SSteve Longerbeam u8 temp; 206019a81c14SSteve Longerbeam int ret; 206119a81c14SSteve Longerbeam 206219a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp); 206319a81c14SSteve Longerbeam if (ret) 206419a81c14SSteve Longerbeam return ret; 2065c2c3f42dSHugues Fruchet 2066c2c3f42dSHugues Fruchet return temp & BIT(0); 206719a81c14SSteve Longerbeam } 206819a81c14SSteve Longerbeam 2069ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable) 2070ce85705aSHugues Fruchet { 2071ce85705aSHugues Fruchet int ret; 2072ce85705aSHugues Fruchet 2073ce85705aSHugues Fruchet /* 2074ce85705aSHugues Fruchet * TIMING TC REG21: 2075ce85705aSHugues Fruchet * - [0]: Horizontal binning enable 2076ce85705aSHugues Fruchet */ 2077ce85705aSHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 2078ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 2079ce85705aSHugues Fruchet if (ret) 2080ce85705aSHugues Fruchet return ret; 2081ce85705aSHugues Fruchet /* 2082ce85705aSHugues Fruchet * TIMING TC REG20: 2083ce85705aSHugues Fruchet * - [0]: Undocumented, but hardcoded init sequences 2084ce85705aSHugues Fruchet * are always setting REG21/REG20 bit 0 to same value... 2085ce85705aSHugues Fruchet */ 2086ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 2087ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 2088ce85705aSHugues Fruchet } 2089ce85705aSHugues Fruchet 209019a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) 209119a81c14SSteve Longerbeam { 20928670d70aSHugues Fruchet struct i2c_client *client = sensor->i2c_client; 209319a81c14SSteve Longerbeam u8 temp, channel = virtual_channel; 209419a81c14SSteve Longerbeam int ret; 209519a81c14SSteve Longerbeam 20968670d70aSHugues Fruchet if (channel > 3) { 20978670d70aSHugues Fruchet dev_err(&client->dev, 20988670d70aSHugues Fruchet "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", 20998670d70aSHugues Fruchet __func__, channel); 210019a81c14SSteve Longerbeam return -EINVAL; 21018670d70aSHugues Fruchet } 210219a81c14SSteve Longerbeam 210319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); 210419a81c14SSteve Longerbeam if (ret) 210519a81c14SSteve Longerbeam return ret; 210619a81c14SSteve Longerbeam temp &= ~(3 << 6); 210719a81c14SSteve Longerbeam temp |= (channel << 6); 210819a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); 210919a81c14SSteve Longerbeam } 211019a81c14SSteve Longerbeam 211119a81c14SSteve Longerbeam static const struct ov5640_mode_info * 211219a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, 211319a81c14SSteve Longerbeam int width, int height, bool nearest) 211419a81c14SSteve Longerbeam { 21153c4a7372SHugues Fruchet const struct ov5640_mode_info *mode; 211619a81c14SSteve Longerbeam 2117086c25f8SMaxime Ripard mode = v4l2_find_nearest_size(ov5640_mode_data, 2118086c25f8SMaxime Ripard ARRAY_SIZE(ov5640_mode_data), 2119*5113d5b3SJacopo Mondi width, height, width, height); 212019a81c14SSteve Longerbeam 21213c4a7372SHugues Fruchet if (!mode || 21223145efcdSJacopo Mondi (!nearest && 2123*5113d5b3SJacopo Mondi (mode->width != width || mode->height != height))) 21243c4a7372SHugues Fruchet return NULL; 212519a81c14SSteve Longerbeam 21265554c80eSAdam Ford /* Check to see if the current mode exceeds the max frame rate */ 21275554c80eSAdam Ford if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps]) 2128981e4454SBenoit Parrot return NULL; 2129981e4454SBenoit Parrot 213019a81c14SSteve Longerbeam return mode; 213119a81c14SSteve Longerbeam } 213219a81c14SSteve Longerbeam 213319a81c14SSteve Longerbeam /* 213419a81c14SSteve Longerbeam * sensor changes between scaling and subsampling, go through 213519a81c14SSteve Longerbeam * exposure calculation 213619a81c14SSteve Longerbeam */ 213741d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, 213841d8d7f5SHugues Fruchet const struct ov5640_mode_info *mode) 213919a81c14SSteve Longerbeam { 214019a81c14SSteve Longerbeam u32 prev_shutter, prev_gain16; 214119a81c14SSteve Longerbeam u32 cap_shutter, cap_gain16; 214219a81c14SSteve Longerbeam u32 cap_sysclk, cap_hts, cap_vts; 214319a81c14SSteve Longerbeam u32 light_freq, cap_bandfilt, cap_maxband; 214419a81c14SSteve Longerbeam u32 cap_gain16_shutter; 214519a81c14SSteve Longerbeam u8 average; 214619a81c14SSteve Longerbeam int ret; 214719a81c14SSteve Longerbeam 214841d8d7f5SHugues Fruchet if (!mode->reg_data) 214919a81c14SSteve Longerbeam return -EINVAL; 215019a81c14SSteve Longerbeam 215119a81c14SSteve Longerbeam /* read preview shutter */ 215219a81c14SSteve Longerbeam ret = ov5640_get_exposure(sensor); 215319a81c14SSteve Longerbeam if (ret < 0) 215419a81c14SSteve Longerbeam return ret; 215519a81c14SSteve Longerbeam prev_shutter = ret; 2156c2c3f42dSHugues Fruchet ret = ov5640_get_binning(sensor); 215719a81c14SSteve Longerbeam if (ret < 0) 215819a81c14SSteve Longerbeam return ret; 215919a81c14SSteve Longerbeam if (ret && mode->id != OV5640_MODE_720P_1280_720 && 216019a81c14SSteve Longerbeam mode->id != OV5640_MODE_1080P_1920_1080) 216119a81c14SSteve Longerbeam prev_shutter *= 2; 216219a81c14SSteve Longerbeam 216319a81c14SSteve Longerbeam /* read preview gain */ 216419a81c14SSteve Longerbeam ret = ov5640_get_gain(sensor); 216519a81c14SSteve Longerbeam if (ret < 0) 216619a81c14SSteve Longerbeam return ret; 216719a81c14SSteve Longerbeam prev_gain16 = ret; 216819a81c14SSteve Longerbeam 216919a81c14SSteve Longerbeam /* get average */ 217019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average); 217119a81c14SSteve Longerbeam if (ret) 217219a81c14SSteve Longerbeam return ret; 217319a81c14SSteve Longerbeam 217419a81c14SSteve Longerbeam /* turn off night mode for capture */ 217519a81c14SSteve Longerbeam ret = ov5640_set_night_mode(sensor); 217619a81c14SSteve Longerbeam if (ret < 0) 217719a81c14SSteve Longerbeam return ret; 217819a81c14SSteve Longerbeam 217919a81c14SSteve Longerbeam /* Write capture setting */ 218019a81c14SSteve Longerbeam ret = ov5640_load_regs(sensor, mode); 218119a81c14SSteve Longerbeam if (ret < 0) 218219a81c14SSteve Longerbeam return ret; 218319a81c14SSteve Longerbeam 218419a81c14SSteve Longerbeam /* read capture VTS */ 218519a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 218619a81c14SSteve Longerbeam if (ret < 0) 218719a81c14SSteve Longerbeam return ret; 218819a81c14SSteve Longerbeam cap_vts = ret; 218919a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 219019a81c14SSteve Longerbeam if (ret < 0) 219119a81c14SSteve Longerbeam return ret; 219219a81c14SSteve Longerbeam if (ret == 0) 219319a81c14SSteve Longerbeam return -EINVAL; 219419a81c14SSteve Longerbeam cap_hts = ret; 219519a81c14SSteve Longerbeam 219619a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 219719a81c14SSteve Longerbeam if (ret < 0) 219819a81c14SSteve Longerbeam return ret; 219919a81c14SSteve Longerbeam if (ret == 0) 220019a81c14SSteve Longerbeam return -EINVAL; 220119a81c14SSteve Longerbeam cap_sysclk = ret; 220219a81c14SSteve Longerbeam 220319a81c14SSteve Longerbeam /* calculate capture banding filter */ 220419a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 220519a81c14SSteve Longerbeam if (ret < 0) 220619a81c14SSteve Longerbeam return ret; 220719a81c14SSteve Longerbeam light_freq = ret; 220819a81c14SSteve Longerbeam 220919a81c14SSteve Longerbeam if (light_freq == 60) { 221019a81c14SSteve Longerbeam /* 60Hz */ 221119a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120; 221219a81c14SSteve Longerbeam } else { 221319a81c14SSteve Longerbeam /* 50Hz */ 221419a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts; 221519a81c14SSteve Longerbeam } 221619a81c14SSteve Longerbeam 221719a81c14SSteve Longerbeam if (!sensor->prev_sysclk) { 221819a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 221919a81c14SSteve Longerbeam if (ret < 0) 222019a81c14SSteve Longerbeam return ret; 222119a81c14SSteve Longerbeam if (ret == 0) 222219a81c14SSteve Longerbeam return -EINVAL; 222319a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 222419a81c14SSteve Longerbeam } 222519a81c14SSteve Longerbeam 222619a81c14SSteve Longerbeam if (!cap_bandfilt) 222719a81c14SSteve Longerbeam return -EINVAL; 222819a81c14SSteve Longerbeam 222919a81c14SSteve Longerbeam cap_maxband = (int)((cap_vts - 4) / cap_bandfilt); 223019a81c14SSteve Longerbeam 223119a81c14SSteve Longerbeam /* calculate capture shutter/gain16 */ 223219a81c14SSteve Longerbeam if (average > sensor->ae_low && average < sensor->ae_high) { 223319a81c14SSteve Longerbeam /* in stable range */ 223419a81c14SSteve Longerbeam cap_gain16_shutter = 223519a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 223619a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 223719a81c14SSteve Longerbeam sensor->prev_hts / cap_hts * 223819a81c14SSteve Longerbeam sensor->ae_target / average; 223919a81c14SSteve Longerbeam } else { 224019a81c14SSteve Longerbeam cap_gain16_shutter = 224119a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 224219a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 224319a81c14SSteve Longerbeam sensor->prev_hts / cap_hts; 224419a81c14SSteve Longerbeam } 224519a81c14SSteve Longerbeam 224619a81c14SSteve Longerbeam /* gain to shutter */ 224719a81c14SSteve Longerbeam if (cap_gain16_shutter < (cap_bandfilt * 16)) { 224819a81c14SSteve Longerbeam /* shutter < 1/100 */ 224919a81c14SSteve Longerbeam cap_shutter = cap_gain16_shutter / 16; 225019a81c14SSteve Longerbeam if (cap_shutter < 1) 225119a81c14SSteve Longerbeam cap_shutter = 1; 225219a81c14SSteve Longerbeam 225319a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 225419a81c14SSteve Longerbeam if (cap_gain16 < 16) 225519a81c14SSteve Longerbeam cap_gain16 = 16; 225619a81c14SSteve Longerbeam } else { 225719a81c14SSteve Longerbeam if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) { 225819a81c14SSteve Longerbeam /* exposure reach max */ 225919a81c14SSteve Longerbeam cap_shutter = cap_bandfilt * cap_maxband; 226019a81c14SSteve Longerbeam if (!cap_shutter) 226119a81c14SSteve Longerbeam return -EINVAL; 226219a81c14SSteve Longerbeam 226319a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 226419a81c14SSteve Longerbeam } else { 226519a81c14SSteve Longerbeam /* 1/100 < (cap_shutter = n/100) =< max */ 226619a81c14SSteve Longerbeam cap_shutter = 226719a81c14SSteve Longerbeam ((int)(cap_gain16_shutter / 16 / cap_bandfilt)) 226819a81c14SSteve Longerbeam * cap_bandfilt; 226919a81c14SSteve Longerbeam if (!cap_shutter) 227019a81c14SSteve Longerbeam return -EINVAL; 227119a81c14SSteve Longerbeam 227219a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 227319a81c14SSteve Longerbeam } 227419a81c14SSteve Longerbeam } 227519a81c14SSteve Longerbeam 227619a81c14SSteve Longerbeam /* set capture gain */ 22773cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, cap_gain16); 227819a81c14SSteve Longerbeam if (ret) 227919a81c14SSteve Longerbeam return ret; 228019a81c14SSteve Longerbeam 228119a81c14SSteve Longerbeam /* write capture shutter */ 228219a81c14SSteve Longerbeam if (cap_shutter > (cap_vts - 4)) { 228319a81c14SSteve Longerbeam cap_vts = cap_shutter + 4; 228419a81c14SSteve Longerbeam ret = ov5640_set_vts(sensor, cap_vts); 228519a81c14SSteve Longerbeam if (ret < 0) 228619a81c14SSteve Longerbeam return ret; 228719a81c14SSteve Longerbeam } 228819a81c14SSteve Longerbeam 228919a81c14SSteve Longerbeam /* set exposure */ 22903cca8ef5SHugues Fruchet return ov5640_set_exposure(sensor, cap_shutter); 229119a81c14SSteve Longerbeam } 229219a81c14SSteve Longerbeam 229319a81c14SSteve Longerbeam /* 229419a81c14SSteve Longerbeam * if sensor changes inside scaling or subsampling 229519a81c14SSteve Longerbeam * change mode directly 229619a81c14SSteve Longerbeam */ 229719a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor, 22983cca8ef5SHugues Fruchet const struct ov5640_mode_info *mode) 229919a81c14SSteve Longerbeam { 230041d8d7f5SHugues Fruchet if (!mode->reg_data) 230119a81c14SSteve Longerbeam return -EINVAL; 230219a81c14SSteve Longerbeam 230319a81c14SSteve Longerbeam /* Write capture setting */ 23043cca8ef5SHugues Fruchet return ov5640_load_regs(sensor, mode); 230519a81c14SSteve Longerbeam } 230619a81c14SSteve Longerbeam 2307985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor) 230819a81c14SSteve Longerbeam { 230919a81c14SSteve Longerbeam const struct ov5640_mode_info *mode = sensor->current_mode; 2310985cdcb0SHugues Fruchet const struct ov5640_mode_info *orig_mode = sensor->last_mode; 231119a81c14SSteve Longerbeam enum ov5640_downsize_mode dn_mode, orig_dn_mode; 23123cca8ef5SHugues Fruchet bool auto_gain = sensor->ctrls.auto_gain->val == 1; 2313dc29a1c1SHugues Fruchet bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; 231419a81c14SSteve Longerbeam int ret; 231519a81c14SSteve Longerbeam 231619a81c14SSteve Longerbeam dn_mode = mode->dn_mode; 231719a81c14SSteve Longerbeam orig_dn_mode = orig_mode->dn_mode; 231819a81c14SSteve Longerbeam 231919a81c14SSteve Longerbeam /* auto gain and exposure must be turned off when changing modes */ 23203cca8ef5SHugues Fruchet if (auto_gain) { 23213cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, false); 232219a81c14SSteve Longerbeam if (ret) 232319a81c14SSteve Longerbeam return ret; 23243cca8ef5SHugues Fruchet } 2325bf4a4b51SMaxime Ripard 23263cca8ef5SHugues Fruchet if (auto_exp) { 2327dc29a1c1SHugues Fruchet ret = ov5640_set_autoexposure(sensor, false); 232819a81c14SSteve Longerbeam if (ret) 23293cca8ef5SHugues Fruchet goto restore_auto_gain; 23303cca8ef5SHugues Fruchet } 233119a81c14SSteve Longerbeam 23326c957ed7SJacopo Mondi if (ov5640_is_csi2(sensor)) 23336c957ed7SJacopo Mondi ret = ov5640_set_mipi_pclk(sensor); 23346c957ed7SJacopo Mondi else 23356c957ed7SJacopo Mondi ret = ov5640_set_dvp_pclk(sensor); 2336aa288248SMaxime Ripard if (ret < 0) 2337aa288248SMaxime Ripard return 0; 2338aa288248SMaxime Ripard 233919a81c14SSteve Longerbeam if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || 234019a81c14SSteve Longerbeam (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { 234119a81c14SSteve Longerbeam /* 234219a81c14SSteve Longerbeam * change between subsampling and scaling 23433cca8ef5SHugues Fruchet * go through exposure calculation 234419a81c14SSteve Longerbeam */ 234519a81c14SSteve Longerbeam ret = ov5640_set_mode_exposure_calc(sensor, mode); 234619a81c14SSteve Longerbeam } else { 234719a81c14SSteve Longerbeam /* 234819a81c14SSteve Longerbeam * change inside subsampling or scaling 234919a81c14SSteve Longerbeam * download firmware directly 235019a81c14SSteve Longerbeam */ 23513cca8ef5SHugues Fruchet ret = ov5640_set_mode_direct(sensor, mode); 235219a81c14SSteve Longerbeam } 235319a81c14SSteve Longerbeam if (ret < 0) 23543cca8ef5SHugues Fruchet goto restore_auto_exp_gain; 23553cca8ef5SHugues Fruchet 23563cca8ef5SHugues Fruchet /* restore auto gain and exposure */ 23573cca8ef5SHugues Fruchet if (auto_gain) 23583cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 23593cca8ef5SHugues Fruchet if (auto_exp) 23603cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 236119a81c14SSteve Longerbeam 2362ce85705aSHugues Fruchet ret = ov5640_set_binning(sensor, dn_mode != SCALING); 2363ce85705aSHugues Fruchet if (ret < 0) 2364ce85705aSHugues Fruchet return ret; 236519a81c14SSteve Longerbeam ret = ov5640_set_ae_target(sensor, sensor->ae_target); 236619a81c14SSteve Longerbeam if (ret < 0) 236719a81c14SSteve Longerbeam return ret; 236819a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 236919a81c14SSteve Longerbeam if (ret < 0) 237019a81c14SSteve Longerbeam return ret; 237119a81c14SSteve Longerbeam ret = ov5640_set_bandingfilter(sensor); 237219a81c14SSteve Longerbeam if (ret < 0) 237319a81c14SSteve Longerbeam return ret; 237419a81c14SSteve Longerbeam ret = ov5640_set_virtual_channel(sensor); 237519a81c14SSteve Longerbeam if (ret < 0) 237619a81c14SSteve Longerbeam return ret; 237719a81c14SSteve Longerbeam 237819a81c14SSteve Longerbeam sensor->pending_mode_change = false; 2379985cdcb0SHugues Fruchet sensor->last_mode = mode; 238019a81c14SSteve Longerbeam 238119a81c14SSteve Longerbeam return 0; 23823cca8ef5SHugues Fruchet 23833cca8ef5SHugues Fruchet restore_auto_exp_gain: 23843cca8ef5SHugues Fruchet if (auto_exp) 23853cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 23863cca8ef5SHugues Fruchet restore_auto_gain: 23873cca8ef5SHugues Fruchet if (auto_gain) 23883cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 23893cca8ef5SHugues Fruchet 23903cca8ef5SHugues Fruchet return ret; 239119a81c14SSteve Longerbeam } 239219a81c14SSteve Longerbeam 239319ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor, 239419ad26f9SAkinobu Mita struct v4l2_mbus_framefmt *format); 239519ad26f9SAkinobu Mita 239619a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */ 239719a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor) 239819a81c14SSteve Longerbeam { 239919a81c14SSteve Longerbeam int ret; 240019a81c14SSteve Longerbeam 240119a81c14SSteve Longerbeam /* first load the initial register values */ 240219a81c14SSteve Longerbeam ret = ov5640_load_regs(sensor, &ov5640_mode_init_data); 240319a81c14SSteve Longerbeam if (ret < 0) 240419a81c14SSteve Longerbeam return ret; 2405985cdcb0SHugues Fruchet sensor->last_mode = &ov5640_mode_init_data; 240619a81c14SSteve Longerbeam 24078f57c2f8SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 24087851fe7aSMaxime Ripard (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | 24097851fe7aSMaxime Ripard ilog2(OV5640_SCLK_ROOT_DIV)); 24108f57c2f8SMaxime Ripard if (ret) 24118f57c2f8SMaxime Ripard return ret; 24128f57c2f8SMaxime Ripard 241319a81c14SSteve Longerbeam /* now restore the last capture mode */ 2414985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 241519ad26f9SAkinobu Mita if (ret < 0) 241619ad26f9SAkinobu Mita return ret; 241719ad26f9SAkinobu Mita 241819ad26f9SAkinobu Mita return ov5640_set_framefmt(sensor, &sensor->fmt); 241919a81c14SSteve Longerbeam } 242019a81c14SSteve Longerbeam 242119a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable) 242219a81c14SSteve Longerbeam { 24231fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); 242419a81c14SSteve Longerbeam } 242519a81c14SSteve Longerbeam 242619a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor) 242719a81c14SSteve Longerbeam { 242819a81c14SSteve Longerbeam if (!sensor->reset_gpio) 242919a81c14SSteve Longerbeam return; 243019a81c14SSteve Longerbeam 24311fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 243219a81c14SSteve Longerbeam 243319a81c14SSteve Longerbeam /* camera power cycle */ 243419a81c14SSteve Longerbeam ov5640_power(sensor, false); 243519a81c14SSteve Longerbeam usleep_range(5000, 10000); 243619a81c14SSteve Longerbeam ov5640_power(sensor, true); 243719a81c14SSteve Longerbeam usleep_range(5000, 10000); 243819a81c14SSteve Longerbeam 24391fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 1); 244019a81c14SSteve Longerbeam usleep_range(1000, 2000); 244119a81c14SSteve Longerbeam 24421fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 24431d4c41f3SLoic Poulain usleep_range(20000, 25000); 244419a81c14SSteve Longerbeam } 244519a81c14SSteve Longerbeam 24460f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor) 244719a81c14SSteve Longerbeam { 24480f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 24490f7acb52SHugues Fruchet int ret; 245019a81c14SSteve Longerbeam 24510f7acb52SHugues Fruchet ret = clk_prepare_enable(sensor->xclk); 24520f7acb52SHugues Fruchet if (ret) { 24530f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable clock\n", 24540f7acb52SHugues Fruchet __func__); 24550f7acb52SHugues Fruchet return ret; 24560f7acb52SHugues Fruchet } 245719a81c14SSteve Longerbeam 245819a81c14SSteve Longerbeam ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, 245919a81c14SSteve Longerbeam sensor->supplies); 24600f7acb52SHugues Fruchet if (ret) { 24610f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable regulators\n", 24620f7acb52SHugues Fruchet __func__); 246319a81c14SSteve Longerbeam goto xclk_off; 24640f7acb52SHugues Fruchet } 246519a81c14SSteve Longerbeam 246619a81c14SSteve Longerbeam ov5640_reset(sensor); 246719a81c14SSteve Longerbeam ov5640_power(sensor, true); 246819a81c14SSteve Longerbeam 246919a81c14SSteve Longerbeam ret = ov5640_init_slave_id(sensor); 247019a81c14SSteve Longerbeam if (ret) 247119a81c14SSteve Longerbeam goto power_off; 247219a81c14SSteve Longerbeam 24730f7acb52SHugues Fruchet return 0; 24740f7acb52SHugues Fruchet 24750f7acb52SHugues Fruchet power_off: 24760f7acb52SHugues Fruchet ov5640_power(sensor, false); 24770f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 24780f7acb52SHugues Fruchet xclk_off: 24790f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 24800f7acb52SHugues Fruchet return ret; 24810f7acb52SHugues Fruchet } 24820f7acb52SHugues Fruchet 24830f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor) 24840f7acb52SHugues Fruchet { 24850f7acb52SHugues Fruchet ov5640_power(sensor, false); 24860f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 24870f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 24880f7acb52SHugues Fruchet } 24890f7acb52SHugues Fruchet 2490b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) 2491b1751ae6SLad Prabhakar { 2492b1751ae6SLad Prabhakar int ret; 2493b1751ae6SLad Prabhakar 2494b1751ae6SLad Prabhakar if (!on) { 2495b1751ae6SLad Prabhakar /* Reset MIPI bus settings to their default values. */ 2496b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2497b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04); 2498b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00); 2499b1751ae6SLad Prabhakar return 0; 2500b1751ae6SLad Prabhakar } 2501b1751ae6SLad Prabhakar 2502b1751ae6SLad Prabhakar /* 2503b1751ae6SLad Prabhakar * Power up MIPI HS Tx and LS Rx; 2 data lanes mode 2504b1751ae6SLad Prabhakar * 2505b1751ae6SLad Prabhakar * 0x300e = 0x40 2506b1751ae6SLad Prabhakar * [7:5] = 010 : 2 data lanes mode (see FIXME note in 2507b1751ae6SLad Prabhakar * "ov5640_set_stream_mipi()") 2508b1751ae6SLad Prabhakar * [4] = 0 : Power up MIPI HS Tx 2509b1751ae6SLad Prabhakar * [3] = 0 : Power up MIPI LS Rx 2510b1751ae6SLad Prabhakar * [2] = 0 : MIPI interface disabled 2511b1751ae6SLad Prabhakar */ 2512b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40); 2513b1751ae6SLad Prabhakar if (ret) 2514b1751ae6SLad Prabhakar return ret; 2515b1751ae6SLad Prabhakar 2516b1751ae6SLad Prabhakar /* 2517b1751ae6SLad Prabhakar * Gate clock and set LP11 in 'no packets mode' (idle) 2518b1751ae6SLad Prabhakar * 2519b1751ae6SLad Prabhakar * 0x4800 = 0x24 2520b1751ae6SLad Prabhakar * [5] = 1 : Gate clock when 'no packets' 2521b1751ae6SLad Prabhakar * [2] = 1 : MIPI bus in LP11 when 'no packets' 2522b1751ae6SLad Prabhakar */ 2523b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24); 2524b1751ae6SLad Prabhakar if (ret) 2525b1751ae6SLad Prabhakar return ret; 2526b1751ae6SLad Prabhakar 2527b1751ae6SLad Prabhakar /* 2528b1751ae6SLad Prabhakar * Set data lanes and clock in LP11 when 'sleeping' 2529b1751ae6SLad Prabhakar * 2530b1751ae6SLad Prabhakar * 0x3019 = 0x70 2531b1751ae6SLad Prabhakar * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping' 2532b1751ae6SLad Prabhakar * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping' 2533b1751ae6SLad Prabhakar * [4] = 1 : MIPI clock lane in LP11 when 'sleeping' 2534b1751ae6SLad Prabhakar */ 2535b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70); 2536b1751ae6SLad Prabhakar if (ret) 2537b1751ae6SLad Prabhakar return ret; 2538b1751ae6SLad Prabhakar 2539b1751ae6SLad Prabhakar /* Give lanes some time to coax into LP11 state. */ 2540b1751ae6SLad Prabhakar usleep_range(500, 1000); 2541b1751ae6SLad Prabhakar 2542b1751ae6SLad Prabhakar return 0; 2543b1751ae6SLad Prabhakar } 2544b1751ae6SLad Prabhakar 2545576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) 2546576f5d4bSLad Prabhakar { 2547311a6408SLad Prabhakar unsigned int flags = sensor->ep.bus.parallel.flags; 254868579b32SHugues Fruchet bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656; 254968579b32SHugues Fruchet u8 polarities = 0; 2550576f5d4bSLad Prabhakar int ret; 2551576f5d4bSLad Prabhakar 2552576f5d4bSLad Prabhakar if (!on) { 2553576f5d4bSLad Prabhakar /* Reset settings to their default values. */ 255468579b32SHugues Fruchet ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00); 2555311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2556311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20); 2557576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00); 2558576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00); 2559576f5d4bSLad Prabhakar return 0; 2560576f5d4bSLad Prabhakar } 2561576f5d4bSLad Prabhakar 2562576f5d4bSLad Prabhakar /* 2563311a6408SLad Prabhakar * Note about parallel port configuration. 2564311a6408SLad Prabhakar * 2565311a6408SLad Prabhakar * When configured in parallel mode, the OV5640 will 2566311a6408SLad Prabhakar * output 10 bits data on DVP data lines [9:0]. 2567311a6408SLad Prabhakar * If only 8 bits data are wanted, the 8 bits data lines 2568311a6408SLad Prabhakar * of the camera interface must be physically connected 2569311a6408SLad Prabhakar * on the DVP data lines [9:2]. 2570311a6408SLad Prabhakar * 2571311a6408SLad Prabhakar * Control lines polarity can be configured through 2572311a6408SLad Prabhakar * devicetree endpoint control lines properties. 2573311a6408SLad Prabhakar * If no endpoint control lines properties are set, 2574311a6408SLad Prabhakar * polarity will be as below: 2575311a6408SLad Prabhakar * - VSYNC: active high 2576311a6408SLad Prabhakar * - HREF: active low 2577311a6408SLad Prabhakar * - PCLK: active low 257868579b32SHugues Fruchet * 257968579b32SHugues Fruchet * VSYNC & HREF are not configured if BT656 bus mode is selected 2580311a6408SLad Prabhakar */ 258168579b32SHugues Fruchet 258268579b32SHugues Fruchet /* 258368579b32SHugues Fruchet * BT656 embedded synchronization configuration 258468579b32SHugues Fruchet * 258568579b32SHugues Fruchet * CCIR656 CTRL00 258668579b32SHugues Fruchet * - [7]: SYNC code selection (0: auto generate sync code, 258768579b32SHugues Fruchet * 1: sync code from regs 0x4732-0x4735) 258868579b32SHugues Fruchet * - [6]: f value in CCIR656 SYNC code when fixed f value 258968579b32SHugues Fruchet * - [5]: Fixed f value 259068579b32SHugues Fruchet * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200, 259168579b32SHugues Fruchet * 01: data from regs 0x4736-0x4738, 10: always keep 0) 259268579b32SHugues Fruchet * - [1]: Clip data disable 259368579b32SHugues Fruchet * - [0]: CCIR656 mode enable 259468579b32SHugues Fruchet * 259568579b32SHugues Fruchet * Default CCIR656 SAV/EAV mode with default codes 259668579b32SHugues Fruchet * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings: 259768579b32SHugues Fruchet * - CCIR656 mode enable 259868579b32SHugues Fruchet * - auto generation of sync codes 259968579b32SHugues Fruchet * - blank toggle data 1'h040/1'h200 260068579b32SHugues Fruchet * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe) 260168579b32SHugues Fruchet */ 260268579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 260368579b32SHugues Fruchet bt656 ? 0x01 : 0x00); 260468579b32SHugues Fruchet if (ret) 260568579b32SHugues Fruchet return ret; 260668579b32SHugues Fruchet 2607311a6408SLad Prabhakar /* 2608311a6408SLad Prabhakar * configure parallel port control lines polarity 2609311a6408SLad Prabhakar * 2610311a6408SLad Prabhakar * POLARITY CTRL0 2611311a6408SLad Prabhakar * - [5]: PCLK polarity (0: active low, 1: active high) 2612311a6408SLad Prabhakar * - [1]: HREF polarity (0: active low, 1: active high) 2613311a6408SLad Prabhakar * - [0]: VSYNC polarity (mismatch here between 2614311a6408SLad Prabhakar * datasheet and hardware, 0 is active high 2615311a6408SLad Prabhakar * and 1 is active low...) 2616311a6408SLad Prabhakar */ 261768579b32SHugues Fruchet if (!bt656) { 2618311a6408SLad Prabhakar if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 261968579b32SHugues Fruchet polarities |= BIT(1); 2620311a6408SLad Prabhakar if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 262168579b32SHugues Fruchet polarities |= BIT(0); 262268579b32SHugues Fruchet } 262368579b32SHugues Fruchet if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 262468579b32SHugues Fruchet polarities |= BIT(5); 2625311a6408SLad Prabhakar 262668579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities); 2627311a6408SLad Prabhakar if (ret) 2628311a6408SLad Prabhakar return ret; 2629311a6408SLad Prabhakar 2630311a6408SLad Prabhakar /* 263168579b32SHugues Fruchet * powerdown MIPI TX/RX PHY & enable DVP 2632311a6408SLad Prabhakar * 2633311a6408SLad Prabhakar * MIPI CONTROL 00 263468579b32SHugues Fruchet * [4] = 1 : Power down MIPI HS Tx 263568579b32SHugues Fruchet * [3] = 1 : Power down MIPI LS Rx 263668579b32SHugues Fruchet * [2] = 0 : DVP enable (MIPI disable) 2637311a6408SLad Prabhakar */ 2638311a6408SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18); 2639311a6408SLad Prabhakar if (ret) 2640311a6408SLad Prabhakar return ret; 2641311a6408SLad Prabhakar 2642311a6408SLad Prabhakar /* 2643576f5d4bSLad Prabhakar * enable VSYNC/HREF/PCLK DVP control lines 2644576f5d4bSLad Prabhakar * & D[9:6] DVP data lines 2645576f5d4bSLad Prabhakar * 2646576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 01 2647576f5d4bSLad Prabhakar * - 6: VSYNC output enable 2648576f5d4bSLad Prabhakar * - 5: HREF output enable 2649576f5d4bSLad Prabhakar * - 4: PCLK output enable 2650576f5d4bSLad Prabhakar * - [3:0]: D[9:6] output enable 2651576f5d4bSLad Prabhakar */ 26524039b037SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 265368579b32SHugues Fruchet bt656 ? 0x1f : 0x7f); 2654576f5d4bSLad Prabhakar if (ret) 2655576f5d4bSLad Prabhakar return ret; 2656576f5d4bSLad Prabhakar 2657576f5d4bSLad Prabhakar /* 2658576f5d4bSLad Prabhakar * enable D[5:0] DVP data lines 2659576f5d4bSLad Prabhakar * 2660576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 02 2661576f5d4bSLad Prabhakar * - [7:2]: D[5:0] output enable 2662576f5d4bSLad Prabhakar */ 2663576f5d4bSLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc); 2664576f5d4bSLad Prabhakar } 2665576f5d4bSLad Prabhakar 26660f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on) 26670f7acb52SHugues Fruchet { 26680f7acb52SHugues Fruchet int ret = 0; 26690f7acb52SHugues Fruchet 26700f7acb52SHugues Fruchet if (on) { 26710f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 26720f7acb52SHugues Fruchet if (ret) 26730f7acb52SHugues Fruchet return ret; 26740f7acb52SHugues Fruchet 267519a81c14SSteve Longerbeam ret = ov5640_restore_mode(sensor); 267619a81c14SSteve Longerbeam if (ret) 267719a81c14SSteve Longerbeam goto power_off; 2678b1751ae6SLad Prabhakar } 267919a81c14SSteve Longerbeam 2680576f5d4bSLad Prabhakar if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) 2681b1751ae6SLad Prabhakar ret = ov5640_set_power_mipi(sensor, on); 2682576f5d4bSLad Prabhakar else 2683576f5d4bSLad Prabhakar ret = ov5640_set_power_dvp(sensor, on); 2684b1751ae6SLad Prabhakar if (ret) 2685b1751ae6SLad Prabhakar goto power_off; 2686aa4bb8b8SJacopo Mondi 2687b1751ae6SLad Prabhakar if (!on) 2688aa4bb8b8SJacopo Mondi ov5640_set_power_off(sensor); 268919a81c14SSteve Longerbeam 269019a81c14SSteve Longerbeam return 0; 269119a81c14SSteve Longerbeam 269219a81c14SSteve Longerbeam power_off: 26930f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 269419a81c14SSteve Longerbeam return ret; 269519a81c14SSteve Longerbeam } 269619a81c14SSteve Longerbeam 269719a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */ 269819a81c14SSteve Longerbeam 269919a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on) 270019a81c14SSteve Longerbeam { 270119a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 270219a81c14SSteve Longerbeam int ret = 0; 270319a81c14SSteve Longerbeam 270419a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 270519a81c14SSteve Longerbeam 270619a81c14SSteve Longerbeam /* 270719a81c14SSteve Longerbeam * If the power count is modified from 0 to != 0 or from != 0 to 0, 270819a81c14SSteve Longerbeam * update the power state. 270919a81c14SSteve Longerbeam */ 271019a81c14SSteve Longerbeam if (sensor->power_count == !on) { 271119a81c14SSteve Longerbeam ret = ov5640_set_power(sensor, !!on); 271219a81c14SSteve Longerbeam if (ret) 271319a81c14SSteve Longerbeam goto out; 271419a81c14SSteve Longerbeam } 271519a81c14SSteve Longerbeam 271619a81c14SSteve Longerbeam /* Update the power count. */ 271719a81c14SSteve Longerbeam sensor->power_count += on ? 1 : -1; 271819a81c14SSteve Longerbeam WARN_ON(sensor->power_count < 0); 271919a81c14SSteve Longerbeam out: 272019a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 272119a81c14SSteve Longerbeam 272219a81c14SSteve Longerbeam if (on && !ret && sensor->power_count == 1) { 272319a81c14SSteve Longerbeam /* restore controls */ 272419a81c14SSteve Longerbeam ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 272519a81c14SSteve Longerbeam } 272619a81c14SSteve Longerbeam 272719a81c14SSteve Longerbeam return ret; 272819a81c14SSteve Longerbeam } 272919a81c14SSteve Longerbeam 273019a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor, 273119a81c14SSteve Longerbeam struct v4l2_fract *fi, 273219a81c14SSteve Longerbeam u32 width, u32 height) 273319a81c14SSteve Longerbeam { 273419a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 27356530a5ebSJagan Teki enum ov5640_frame_rate rate = OV5640_15_FPS; 2736f6cc192fSMaxime Ripard int minfps, maxfps, best_fps, fps; 2737f6cc192fSMaxime Ripard int i; 273819a81c14SSteve Longerbeam 273919a81c14SSteve Longerbeam minfps = ov5640_framerates[OV5640_15_FPS]; 2740e823fb16SMaxime Ripard maxfps = ov5640_framerates[OV5640_60_FPS]; 274119a81c14SSteve Longerbeam 274219a81c14SSteve Longerbeam if (fi->numerator == 0) { 274319a81c14SSteve Longerbeam fi->denominator = maxfps; 274419a81c14SSteve Longerbeam fi->numerator = 1; 2745e823fb16SMaxime Ripard rate = OV5640_60_FPS; 2746e823fb16SMaxime Ripard goto find_mode; 274719a81c14SSteve Longerbeam } 274819a81c14SSteve Longerbeam 2749f6cc192fSMaxime Ripard fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator), 2750f6cc192fSMaxime Ripard minfps, maxfps); 2751f6cc192fSMaxime Ripard 2752f6cc192fSMaxime Ripard best_fps = minfps; 2753f6cc192fSMaxime Ripard for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) { 2754f6cc192fSMaxime Ripard int curr_fps = ov5640_framerates[i]; 2755f6cc192fSMaxime Ripard 2756f6cc192fSMaxime Ripard if (abs(curr_fps - fps) < abs(best_fps - fps)) { 2757f6cc192fSMaxime Ripard best_fps = curr_fps; 2758f6cc192fSMaxime Ripard rate = i; 2759f6cc192fSMaxime Ripard } 2760f6cc192fSMaxime Ripard } 276119a81c14SSteve Longerbeam 276219a81c14SSteve Longerbeam fi->numerator = 1; 2763f6cc192fSMaxime Ripard fi->denominator = best_fps; 276419a81c14SSteve Longerbeam 2765e823fb16SMaxime Ripard find_mode: 27665a3ad937SMaxime Ripard mode = ov5640_find_mode(sensor, rate, width, height, false); 27675a3ad937SMaxime Ripard return mode ? rate : -EINVAL; 276819a81c14SSteve Longerbeam } 276919a81c14SSteve Longerbeam 277019a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd, 27710d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 277219a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 277319a81c14SSteve Longerbeam { 277419a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 277519a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt; 277619a81c14SSteve Longerbeam 277719a81c14SSteve Longerbeam if (format->pad != 0) 277819a81c14SSteve Longerbeam return -EINVAL; 277919a81c14SSteve Longerbeam 278019a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 278119a81c14SSteve Longerbeam 278219a81c14SSteve Longerbeam if (format->which == V4L2_SUBDEV_FORMAT_TRY) 27830d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 278419a81c14SSteve Longerbeam format->pad); 278519a81c14SSteve Longerbeam else 278619a81c14SSteve Longerbeam fmt = &sensor->fmt; 278719a81c14SSteve Longerbeam 278819a81c14SSteve Longerbeam format->format = *fmt; 278919a81c14SSteve Longerbeam 279019a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 279119a81c14SSteve Longerbeam 279219a81c14SSteve Longerbeam return 0; 279319a81c14SSteve Longerbeam } 279419a81c14SSteve Longerbeam 279519a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, 279619a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt, 279719a81c14SSteve Longerbeam enum ov5640_frame_rate fr, 279819a81c14SSteve Longerbeam const struct ov5640_mode_info **new_mode) 279919a81c14SSteve Longerbeam { 280019a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 280119a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 2802e3ee691dSHugues Fruchet int i; 280319a81c14SSteve Longerbeam 280419a81c14SSteve Longerbeam mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); 280519a81c14SSteve Longerbeam if (!mode) 280619a81c14SSteve Longerbeam return -EINVAL; 2807*5113d5b3SJacopo Mondi fmt->width = mode->width; 2808*5113d5b3SJacopo Mondi fmt->height = mode->height; 280919a81c14SSteve Longerbeam 281019a81c14SSteve Longerbeam if (new_mode) 281119a81c14SSteve Longerbeam *new_mode = mode; 2812e3ee691dSHugues Fruchet 2813e3ee691dSHugues Fruchet for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) 2814e3ee691dSHugues Fruchet if (ov5640_formats[i].code == fmt->code) 2815e3ee691dSHugues Fruchet break; 2816e3ee691dSHugues Fruchet if (i >= ARRAY_SIZE(ov5640_formats)) 2817e6441fdeSHugues Fruchet i = 0; 2818e6441fdeSHugues Fruchet 2819e6441fdeSHugues Fruchet fmt->code = ov5640_formats[i].code; 2820e6441fdeSHugues Fruchet fmt->colorspace = ov5640_formats[i].colorspace; 2821e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 2822e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 2823e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 2824e3ee691dSHugues Fruchet 282519a81c14SSteve Longerbeam return 0; 282619a81c14SSteve Longerbeam } 282719a81c14SSteve Longerbeam 28283c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) 28293c28588fSJacopo Mondi { 28303c28588fSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 28313c28588fSJacopo Mondi enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; 28323c28588fSJacopo Mondi struct v4l2_mbus_framefmt *fmt = &sensor->fmt; 28333c28588fSJacopo Mondi unsigned int i = 0; 28343c28588fSJacopo Mondi u32 pixel_rate; 28353c28588fSJacopo Mondi s64 link_freq; 28363c28588fSJacopo Mondi u32 num_lanes; 28373c28588fSJacopo Mondi u32 bpp; 28383c28588fSJacopo Mondi 28393c28588fSJacopo Mondi /* 28403c28588fSJacopo Mondi * Update the pixel rate control value. 28413c28588fSJacopo Mondi * 28423c28588fSJacopo Mondi * For DVP mode, maintain the pixel rate calculation using fixed FPS. 28433c28588fSJacopo Mondi */ 28443c28588fSJacopo Mondi if (!ov5640_is_csi2(sensor)) { 28453c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 28463c28588fSJacopo Mondi ov5640_calc_pixel_rate(sensor)); 28473c28588fSJacopo Mondi 28483c28588fSJacopo Mondi return 0; 28493c28588fSJacopo Mondi } 28503c28588fSJacopo Mondi 28513c28588fSJacopo Mondi /* 28523c28588fSJacopo Mondi * The MIPI CSI-2 link frequency should comply with the CSI-2 28533c28588fSJacopo Mondi * specification and be lower than 1GHz. 28543c28588fSJacopo Mondi * 28553c28588fSJacopo Mondi * Start from the suggested pixel_rate for the current mode and 28563c28588fSJacopo Mondi * progressively slow it down if it exceeds 1GHz. 28573c28588fSJacopo Mondi */ 28583c28588fSJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 28593c28588fSJacopo Mondi bpp = ov5640_code_to_bpp(fmt->code); 28603c28588fSJacopo Mondi do { 28613c28588fSJacopo Mondi pixel_rate = ov5640_pixel_rates[pixel_rate_id]; 28623c28588fSJacopo Mondi link_freq = pixel_rate * bpp / (2 * num_lanes); 28633c28588fSJacopo Mondi } while (link_freq >= 1000000000U && 28643c28588fSJacopo Mondi ++pixel_rate_id < OV5640_NUM_PIXEL_RATES); 28653c28588fSJacopo Mondi 28663c28588fSJacopo Mondi sensor->current_link_freq = link_freq; 28673c28588fSJacopo Mondi 28683c28588fSJacopo Mondi /* 28693c28588fSJacopo Mondi * Higher link rates require the clock tree to be programmed with 28703c28588fSJacopo Mondi * 'mipi_div' = 1; this has the effect of halving the actual output 28713c28588fSJacopo Mondi * pixel rate in the MIPI domain. 28723c28588fSJacopo Mondi * 28733c28588fSJacopo Mondi * Adjust the pixel rate and link frequency control value to report it 28743c28588fSJacopo Mondi * correctly to userspace. 28753c28588fSJacopo Mondi */ 28763c28588fSJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) { 28773c28588fSJacopo Mondi pixel_rate /= 2; 28783c28588fSJacopo Mondi link_freq /= 2; 28793c28588fSJacopo Mondi } 28803c28588fSJacopo Mondi 28813c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) { 28823c28588fSJacopo Mondi if (ov5640_csi2_link_freqs[i] == link_freq) 28833c28588fSJacopo Mondi break; 28843c28588fSJacopo Mondi } 28853c28588fSJacopo Mondi WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs)); 28863c28588fSJacopo Mondi 28873c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); 28883c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); 28893c28588fSJacopo Mondi 28903c28588fSJacopo Mondi return 0; 28913c28588fSJacopo Mondi } 28923c28588fSJacopo Mondi 289319a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd, 28940d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 289519a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 289619a81c14SSteve Longerbeam { 289719a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 289819a81c14SSteve Longerbeam const struct ov5640_mode_info *new_mode; 2899e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *mbus_fmt = &format->format; 290019a81c14SSteve Longerbeam int ret; 290119a81c14SSteve Longerbeam 290219a81c14SSteve Longerbeam if (format->pad != 0) 290319a81c14SSteve Longerbeam return -EINVAL; 290419a81c14SSteve Longerbeam 290519a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 290619a81c14SSteve Longerbeam 290719a81c14SSteve Longerbeam if (sensor->streaming) { 290819a81c14SSteve Longerbeam ret = -EBUSY; 290919a81c14SSteve Longerbeam goto out; 291019a81c14SSteve Longerbeam } 291119a81c14SSteve Longerbeam 2912e6441fdeSHugues Fruchet ret = ov5640_try_fmt_internal(sd, mbus_fmt, 291319a81c14SSteve Longerbeam sensor->current_fr, &new_mode); 291419a81c14SSteve Longerbeam if (ret) 291519a81c14SSteve Longerbeam goto out; 291619a81c14SSteve Longerbeam 2917e738f5ddSMirela Rabulea if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 2918e738f5ddSMirela Rabulea *v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt; 2919e738f5ddSMirela Rabulea goto out; 2920e738f5ddSMirela Rabulea } 292119a81c14SSteve Longerbeam 29226949d864SHugues Fruchet if (new_mode != sensor->current_mode) { 292319a81c14SSteve Longerbeam sensor->current_mode = new_mode; 292419a81c14SSteve Longerbeam sensor->pending_mode_change = true; 29256949d864SHugues Fruchet } 292607115449SJacopo Mondi if (mbus_fmt->code != sensor->fmt.code) 2927fb98e29fSHugues Fruchet sensor->pending_fmt_change = true; 292807115449SJacopo Mondi 2929e738f5ddSMirela Rabulea /* update format even if code is unchanged, resolution might change */ 2930e738f5ddSMirela Rabulea sensor->fmt = *mbus_fmt; 2931e738f5ddSMirela Rabulea 29323c28588fSJacopo Mondi ov5640_update_pixel_rate(sensor); 29333c28588fSJacopo Mondi 293419a81c14SSteve Longerbeam out: 293519a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 293619a81c14SSteve Longerbeam return ret; 293719a81c14SSteve Longerbeam } 293819a81c14SSteve Longerbeam 2939e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor, 2940e3ee691dSHugues Fruchet struct v4l2_mbus_framefmt *format) 2941e3ee691dSHugues Fruchet { 2942e3ee691dSHugues Fruchet int ret = 0; 2943d47c4126SHugues Fruchet bool is_jpeg = false; 2944b7ed3abdSLoic Poulain u8 fmt, mux; 2945e3ee691dSHugues Fruchet 2946e3ee691dSHugues Fruchet switch (format->code) { 29471536fbdbSXavier Roumegue case MEDIA_BUS_FMT_UYVY8_1X16: 2948e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_UYVY8_2X8: 2949e3ee691dSHugues Fruchet /* YUV422, UYVY */ 2950b7ed3abdSLoic Poulain fmt = 0x3f; 2951b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2952e3ee691dSHugues Fruchet break; 29531536fbdbSXavier Roumegue case MEDIA_BUS_FMT_YUYV8_1X16: 2954e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_YUYV8_2X8: 2955e3ee691dSHugues Fruchet /* YUV422, YUYV */ 2956b7ed3abdSLoic Poulain fmt = 0x30; 2957b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2958e3ee691dSHugues Fruchet break; 2959e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_LE: 2960e3ee691dSHugues Fruchet /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ 2961b7ed3abdSLoic Poulain fmt = 0x6F; 2962b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RGB; 2963e3ee691dSHugues Fruchet break; 2964e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_BE: 2965e3ee691dSHugues Fruchet /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ 2966b7ed3abdSLoic Poulain fmt = 0x61; 2967b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RGB; 2968e3ee691dSHugues Fruchet break; 2969d47c4126SHugues Fruchet case MEDIA_BUS_FMT_JPEG_1X8: 2970d47c4126SHugues Fruchet /* YUV422, YUYV */ 2971b7ed3abdSLoic Poulain fmt = 0x30; 2972b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2973d47c4126SHugues Fruchet is_jpeg = true; 2974d47c4126SHugues Fruchet break; 2975b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SBGGR8_1X8: 2976b7ed3abdSLoic Poulain /* Raw, BGBG... / GRGR... */ 2977b7ed3abdSLoic Poulain fmt = 0x00; 2978b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2979b7ed3abdSLoic Poulain break; 2980b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SGBRG8_1X8: 2981b7ed3abdSLoic Poulain /* Raw bayer, GBGB... / RGRG... */ 2982b7ed3abdSLoic Poulain fmt = 0x01; 2983b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2984b7ed3abdSLoic Poulain break; 2985b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SGRBG8_1X8: 2986b7ed3abdSLoic Poulain /* Raw bayer, GRGR... / BGBG... */ 2987b7ed3abdSLoic Poulain fmt = 0x02; 2988b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2989b7ed3abdSLoic Poulain break; 2990b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SRGGB8_1X8: 2991b7ed3abdSLoic Poulain /* Raw bayer, RGRG... / GBGB... */ 2992b7ed3abdSLoic Poulain fmt = 0x03; 2993b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2994b7ed3abdSLoic Poulain break; 2995e3ee691dSHugues Fruchet default: 2996e3ee691dSHugues Fruchet return -EINVAL; 2997e3ee691dSHugues Fruchet } 2998e3ee691dSHugues Fruchet 2999e3ee691dSHugues Fruchet /* FORMAT CONTROL00: YUV and RGB formatting */ 3000b7ed3abdSLoic Poulain ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); 3001e3ee691dSHugues Fruchet if (ret) 3002e3ee691dSHugues Fruchet return ret; 3003e3ee691dSHugues Fruchet 3004e3ee691dSHugues Fruchet /* FORMAT MUX CONTROL: ISP YUV or RGB */ 3005b7ed3abdSLoic Poulain ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); 3006d47c4126SHugues Fruchet if (ret) 3007d47c4126SHugues Fruchet return ret; 3008d47c4126SHugues Fruchet 3009d47c4126SHugues Fruchet /* 3010d47c4126SHugues Fruchet * TIMING TC REG21: 3011d47c4126SHugues Fruchet * - [5]: JPEG enable 3012d47c4126SHugues Fruchet */ 3013d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 3014d47c4126SHugues Fruchet BIT(5), is_jpeg ? BIT(5) : 0); 3015d47c4126SHugues Fruchet if (ret) 3016d47c4126SHugues Fruchet return ret; 3017d47c4126SHugues Fruchet 3018d47c4126SHugues Fruchet /* 3019d47c4126SHugues Fruchet * SYSTEM RESET02: 3020d47c4126SHugues Fruchet * - [4]: Reset JFIFO 3021d47c4126SHugues Fruchet * - [3]: Reset SFIFO 3022d47c4126SHugues Fruchet * - [2]: Reset JPEG 3023d47c4126SHugues Fruchet */ 3024d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, 3025d47c4126SHugues Fruchet BIT(4) | BIT(3) | BIT(2), 3026d47c4126SHugues Fruchet is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); 3027d47c4126SHugues Fruchet if (ret) 3028d47c4126SHugues Fruchet return ret; 3029d47c4126SHugues Fruchet 3030d47c4126SHugues Fruchet /* 3031d47c4126SHugues Fruchet * CLOCK ENABLE02: 3032d47c4126SHugues Fruchet * - [5]: Enable JPEG 2x clock 3033d47c4126SHugues Fruchet * - [3]: Enable JPEG clock 3034d47c4126SHugues Fruchet */ 3035d47c4126SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, 3036d47c4126SHugues Fruchet BIT(5) | BIT(3), 3037d47c4126SHugues Fruchet is_jpeg ? (BIT(5) | BIT(3)) : 0); 3038e3ee691dSHugues Fruchet } 303919a81c14SSteve Longerbeam 304019a81c14SSteve Longerbeam /* 304119a81c14SSteve Longerbeam * Sensor Controls. 304219a81c14SSteve Longerbeam */ 304319a81c14SSteve Longerbeam 304419a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value) 304519a81c14SSteve Longerbeam { 304619a81c14SSteve Longerbeam int ret; 304719a81c14SSteve Longerbeam 304819a81c14SSteve Longerbeam if (value) { 304919a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 305019a81c14SSteve Longerbeam BIT(0), BIT(0)); 305119a81c14SSteve Longerbeam if (ret) 305219a81c14SSteve Longerbeam return ret; 305319a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value); 305419a81c14SSteve Longerbeam } else { 305519a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0); 305619a81c14SSteve Longerbeam } 305719a81c14SSteve Longerbeam 305819a81c14SSteve Longerbeam return ret; 305919a81c14SSteve Longerbeam } 306019a81c14SSteve Longerbeam 306119a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value) 306219a81c14SSteve Longerbeam { 306319a81c14SSteve Longerbeam int ret; 306419a81c14SSteve Longerbeam 306519a81c14SSteve Longerbeam if (value) { 306619a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 306719a81c14SSteve Longerbeam BIT(2), BIT(2)); 306819a81c14SSteve Longerbeam if (ret) 306919a81c14SSteve Longerbeam return ret; 307019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5, 307119a81c14SSteve Longerbeam value & 0xff); 307219a81c14SSteve Longerbeam } else { 307319a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0); 307419a81c14SSteve Longerbeam } 307519a81c14SSteve Longerbeam 307619a81c14SSteve Longerbeam return ret; 307719a81c14SSteve Longerbeam } 307819a81c14SSteve Longerbeam 307919a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value) 308019a81c14SSteve Longerbeam { 308119a81c14SSteve Longerbeam int ret; 308219a81c14SSteve Longerbeam 308319a81c14SSteve Longerbeam if (value) { 308419a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 308519a81c14SSteve Longerbeam BIT(1), BIT(1)); 308619a81c14SSteve Longerbeam if (ret) 308719a81c14SSteve Longerbeam return ret; 308819a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3, 308919a81c14SSteve Longerbeam value & 0xff); 309019a81c14SSteve Longerbeam if (ret) 309119a81c14SSteve Longerbeam return ret; 309219a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4, 309319a81c14SSteve Longerbeam value & 0xff); 309419a81c14SSteve Longerbeam } else { 309519a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0); 309619a81c14SSteve Longerbeam } 309719a81c14SSteve Longerbeam 309819a81c14SSteve Longerbeam return ret; 309919a81c14SSteve Longerbeam } 310019a81c14SSteve Longerbeam 310119a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb) 310219a81c14SSteve Longerbeam { 310319a81c14SSteve Longerbeam int ret; 310419a81c14SSteve Longerbeam 310519a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL, 310619a81c14SSteve Longerbeam BIT(0), awb ? 0 : 1); 310719a81c14SSteve Longerbeam if (ret) 310819a81c14SSteve Longerbeam return ret; 310919a81c14SSteve Longerbeam 311019a81c14SSteve Longerbeam if (!awb) { 311119a81c14SSteve Longerbeam u16 red = (u16)sensor->ctrls.red_balance->val; 311219a81c14SSteve Longerbeam u16 blue = (u16)sensor->ctrls.blue_balance->val; 311319a81c14SSteve Longerbeam 311419a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red); 311519a81c14SSteve Longerbeam if (ret) 311619a81c14SSteve Longerbeam return ret; 311719a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue); 311819a81c14SSteve Longerbeam } 311919a81c14SSteve Longerbeam 312019a81c14SSteve Longerbeam return ret; 312119a81c14SSteve Longerbeam } 312219a81c14SSteve Longerbeam 31233cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, 31243cca8ef5SHugues Fruchet enum v4l2_exposure_auto_type auto_exposure) 312519a81c14SSteve Longerbeam { 312619a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 31273cca8ef5SHugues Fruchet bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO); 312819a81c14SSteve Longerbeam int ret = 0; 312919a81c14SSteve Longerbeam 313019a81c14SSteve Longerbeam if (ctrls->auto_exp->is_new) { 31313cca8ef5SHugues Fruchet ret = ov5640_set_autoexposure(sensor, auto_exp); 313219a81c14SSteve Longerbeam if (ret) 313319a81c14SSteve Longerbeam return ret; 313419a81c14SSteve Longerbeam } 313519a81c14SSteve Longerbeam 31363cca8ef5SHugues Fruchet if (!auto_exp && ctrls->exposure->is_new) { 313719a81c14SSteve Longerbeam u16 max_exp; 313819a81c14SSteve Longerbeam 313919a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS, 314019a81c14SSteve Longerbeam &max_exp); 314119a81c14SSteve Longerbeam if (ret) 314219a81c14SSteve Longerbeam return ret; 314319a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 314419a81c14SSteve Longerbeam if (ret < 0) 314519a81c14SSteve Longerbeam return ret; 314619a81c14SSteve Longerbeam max_exp += ret; 31476146fde3SHugues Fruchet ret = 0; 314819a81c14SSteve Longerbeam 314919a81c14SSteve Longerbeam if (ctrls->exposure->val < max_exp) 315019a81c14SSteve Longerbeam ret = ov5640_set_exposure(sensor, ctrls->exposure->val); 315119a81c14SSteve Longerbeam } 315219a81c14SSteve Longerbeam 315319a81c14SSteve Longerbeam return ret; 315419a81c14SSteve Longerbeam } 315519a81c14SSteve Longerbeam 31563cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) 315719a81c14SSteve Longerbeam { 315819a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 315919a81c14SSteve Longerbeam int ret = 0; 316019a81c14SSteve Longerbeam 316119a81c14SSteve Longerbeam if (ctrls->auto_gain->is_new) { 31623cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, auto_gain); 316319a81c14SSteve Longerbeam if (ret) 316419a81c14SSteve Longerbeam return ret; 316519a81c14SSteve Longerbeam } 316619a81c14SSteve Longerbeam 31673cca8ef5SHugues Fruchet if (!auto_gain && ctrls->gain->is_new) 31683cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, ctrls->gain->val); 316919a81c14SSteve Longerbeam 317019a81c14SSteve Longerbeam return ret; 317119a81c14SSteve Longerbeam } 317219a81c14SSteve Longerbeam 31739f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = { 31749f6d7bacSChen-Yu Tsai "Disabled", 31759f6d7bacSChen-Yu Tsai "Color bars", 3176bddc5cdfSChen-Yu Tsai "Color bars w/ rolling bar", 3177bddc5cdfSChen-Yu Tsai "Color squares", 3178bddc5cdfSChen-Yu Tsai "Color squares w/ rolling bar", 31799f6d7bacSChen-Yu Tsai }; 31809f6d7bacSChen-Yu Tsai 3181a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE BIT(7) 3182a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ 3183a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT BIT(5) 3184a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ 3185a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD (0 << 2) 3186a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) 3187a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) 3188a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) 3189a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR (0 << 0) 3190a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM (1 << 0) 3191a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE (2 << 0) 3192a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK (3 << 0) 3193a0c29afbSChen-Yu Tsai 3194a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = { 3195a0c29afbSChen-Yu Tsai 0, 31962aff1fc3SChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | 3197a0c29afbSChen-Yu Tsai OV5640_TEST_BAR, 3198bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | 3199bddc5cdfSChen-Yu Tsai OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, 3200bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, 3201bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, 3202a0c29afbSChen-Yu Tsai }; 3203a0c29afbSChen-Yu Tsai 320419a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) 320519a81c14SSteve Longerbeam { 3206a0c29afbSChen-Yu Tsai return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, 3207a0c29afbSChen-Yu Tsai test_pattern_val[value]); 320819a81c14SSteve Longerbeam } 320919a81c14SSteve Longerbeam 32101068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) 32111068fecaSMylène Josserand { 32121068fecaSMylène Josserand int ret; 32131068fecaSMylène Josserand 32141068fecaSMylène Josserand ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7), 32151068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ? 32161068fecaSMylène Josserand 0 : BIT(7)); 32171068fecaSMylène Josserand if (ret) 32181068fecaSMylène Josserand return ret; 32191068fecaSMylène Josserand 32201068fecaSMylène Josserand return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2), 32211068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ? 32221068fecaSMylène Josserand BIT(2) : 0); 32231068fecaSMylène Josserand } 32241068fecaSMylène Josserand 3225ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value) 3226ce85705aSHugues Fruchet { 3227ce85705aSHugues Fruchet /* 3228c3f3ba3eSHugues Fruchet * If sensor is mounted upside down, mirror logic is inversed. 3229c3f3ba3eSHugues Fruchet * 3230ce85705aSHugues Fruchet * Sensor is a BSI (Back Side Illuminated) one, 3231ce85705aSHugues Fruchet * so image captured is physically mirrored. 3232ce85705aSHugues Fruchet * This is why mirror logic is inversed in 3233ce85705aSHugues Fruchet * order to cancel this mirror effect. 3234ce85705aSHugues Fruchet */ 3235ce85705aSHugues Fruchet 3236ce85705aSHugues Fruchet /* 3237ce85705aSHugues Fruchet * TIMING TC REG21: 3238ce85705aSHugues Fruchet * - [2]: ISP mirror 3239ce85705aSHugues Fruchet * - [1]: Sensor mirror 3240ce85705aSHugues Fruchet */ 3241ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 3242ce85705aSHugues Fruchet BIT(2) | BIT(1), 3243c3f3ba3eSHugues Fruchet (!(value ^ sensor->upside_down)) ? 3244c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3245ce85705aSHugues Fruchet } 3246ce85705aSHugues Fruchet 3247ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) 3248ce85705aSHugues Fruchet { 3249c3f3ba3eSHugues Fruchet /* If sensor is mounted upside down, flip logic is inversed */ 3250c3f3ba3eSHugues Fruchet 3251ce85705aSHugues Fruchet /* 3252ce85705aSHugues Fruchet * TIMING TC REG20: 3253ce85705aSHugues Fruchet * - [2]: ISP vflip 3254ce85705aSHugues Fruchet * - [1]: Sensor vflip 3255ce85705aSHugues Fruchet */ 3256ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 3257ce85705aSHugues Fruchet BIT(2) | BIT(1), 3258c3f3ba3eSHugues Fruchet (value ^ sensor->upside_down) ? 3259c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3260ce85705aSHugues Fruchet } 3261ce85705aSHugues Fruchet 326219a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 326319a81c14SSteve Longerbeam { 326419a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 326519a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 326619a81c14SSteve Longerbeam int val; 326719a81c14SSteve Longerbeam 326819a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 326919a81c14SSteve Longerbeam 327019a81c14SSteve Longerbeam switch (ctrl->id) { 327119a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 327219a81c14SSteve Longerbeam val = ov5640_get_gain(sensor); 327319a81c14SSteve Longerbeam if (val < 0) 327419a81c14SSteve Longerbeam return val; 327519a81c14SSteve Longerbeam sensor->ctrls.gain->val = val; 327619a81c14SSteve Longerbeam break; 327719a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 327819a81c14SSteve Longerbeam val = ov5640_get_exposure(sensor); 327919a81c14SSteve Longerbeam if (val < 0) 328019a81c14SSteve Longerbeam return val; 328119a81c14SSteve Longerbeam sensor->ctrls.exposure->val = val; 328219a81c14SSteve Longerbeam break; 328319a81c14SSteve Longerbeam } 328419a81c14SSteve Longerbeam 328519a81c14SSteve Longerbeam return 0; 328619a81c14SSteve Longerbeam } 328719a81c14SSteve Longerbeam 328819a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) 328919a81c14SSteve Longerbeam { 329019a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 329119a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 329219a81c14SSteve Longerbeam int ret; 329319a81c14SSteve Longerbeam 329419a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 329519a81c14SSteve Longerbeam 329619a81c14SSteve Longerbeam /* 329719a81c14SSteve Longerbeam * If the device is not powered up by the host driver do 329819a81c14SSteve Longerbeam * not apply any controls to H/W at this time. Instead 329919a81c14SSteve Longerbeam * the controls will be restored right after power-up. 330019a81c14SSteve Longerbeam */ 330119a81c14SSteve Longerbeam if (sensor->power_count == 0) 330219a81c14SSteve Longerbeam return 0; 330319a81c14SSteve Longerbeam 330419a81c14SSteve Longerbeam switch (ctrl->id) { 330519a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 330619a81c14SSteve Longerbeam ret = ov5640_set_ctrl_gain(sensor, ctrl->val); 330719a81c14SSteve Longerbeam break; 330819a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 330919a81c14SSteve Longerbeam ret = ov5640_set_ctrl_exposure(sensor, ctrl->val); 331019a81c14SSteve Longerbeam break; 331119a81c14SSteve Longerbeam case V4L2_CID_AUTO_WHITE_BALANCE: 331219a81c14SSteve Longerbeam ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val); 331319a81c14SSteve Longerbeam break; 331419a81c14SSteve Longerbeam case V4L2_CID_HUE: 331519a81c14SSteve Longerbeam ret = ov5640_set_ctrl_hue(sensor, ctrl->val); 331619a81c14SSteve Longerbeam break; 331719a81c14SSteve Longerbeam case V4L2_CID_CONTRAST: 331819a81c14SSteve Longerbeam ret = ov5640_set_ctrl_contrast(sensor, ctrl->val); 331919a81c14SSteve Longerbeam break; 332019a81c14SSteve Longerbeam case V4L2_CID_SATURATION: 332119a81c14SSteve Longerbeam ret = ov5640_set_ctrl_saturation(sensor, ctrl->val); 332219a81c14SSteve Longerbeam break; 332319a81c14SSteve Longerbeam case V4L2_CID_TEST_PATTERN: 332419a81c14SSteve Longerbeam ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val); 332519a81c14SSteve Longerbeam break; 33261068fecaSMylène Josserand case V4L2_CID_POWER_LINE_FREQUENCY: 33271068fecaSMylène Josserand ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val); 33281068fecaSMylène Josserand break; 3329ce85705aSHugues Fruchet case V4L2_CID_HFLIP: 3330ce85705aSHugues Fruchet ret = ov5640_set_ctrl_hflip(sensor, ctrl->val); 3331ce85705aSHugues Fruchet break; 3332ce85705aSHugues Fruchet case V4L2_CID_VFLIP: 3333ce85705aSHugues Fruchet ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); 3334ce85705aSHugues Fruchet break; 333519a81c14SSteve Longerbeam default: 333619a81c14SSteve Longerbeam ret = -EINVAL; 333719a81c14SSteve Longerbeam break; 333819a81c14SSteve Longerbeam } 333919a81c14SSteve Longerbeam 334019a81c14SSteve Longerbeam return ret; 334119a81c14SSteve Longerbeam } 334219a81c14SSteve Longerbeam 334319a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { 334419a81c14SSteve Longerbeam .g_volatile_ctrl = ov5640_g_volatile_ctrl, 334519a81c14SSteve Longerbeam .s_ctrl = ov5640_s_ctrl, 334619a81c14SSteve Longerbeam }; 334719a81c14SSteve Longerbeam 334819a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor) 334919a81c14SSteve Longerbeam { 335022845bf2SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 335119a81c14SSteve Longerbeam const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; 335219a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 335319a81c14SSteve Longerbeam struct v4l2_ctrl_handler *hdl = &ctrls->handler; 335419a81c14SSteve Longerbeam int ret; 335519a81c14SSteve Longerbeam 335619a81c14SSteve Longerbeam v4l2_ctrl_handler_init(hdl, 32); 335719a81c14SSteve Longerbeam 335819a81c14SSteve Longerbeam /* we can use our own mutex for the ctrl lock */ 335919a81c14SSteve Longerbeam hdl->lock = &sensor->lock; 336019a81c14SSteve Longerbeam 3361cc196e48SBenoit Parrot /* Clock related controls */ 3362cc196e48SBenoit Parrot ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 336322845bf2SJacopo Mondi ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1], 336422845bf2SJacopo Mondi ov5640_pixel_rates[0], 1, 336522845bf2SJacopo Mondi ov5640_pixel_rates[mode->pixel_rate]); 3366cc196e48SBenoit Parrot 33677a3b8d4bSJacopo Mondi ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, 33687a3b8d4bSJacopo Mondi V4L2_CID_LINK_FREQ, 33697a3b8d4bSJacopo Mondi ARRAY_SIZE(ov5640_csi2_link_freqs) - 1, 33707a3b8d4bSJacopo Mondi OV5640_DEFAULT_LINK_FREQ, 33717a3b8d4bSJacopo Mondi ov5640_csi2_link_freqs); 33727a3b8d4bSJacopo Mondi 337319a81c14SSteve Longerbeam /* Auto/manual white balance */ 337419a81c14SSteve Longerbeam ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, 337519a81c14SSteve Longerbeam V4L2_CID_AUTO_WHITE_BALANCE, 337619a81c14SSteve Longerbeam 0, 1, 1, 1); 337719a81c14SSteve Longerbeam ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, 337819a81c14SSteve Longerbeam 0, 4095, 1, 0); 337919a81c14SSteve Longerbeam ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, 338019a81c14SSteve Longerbeam 0, 4095, 1, 0); 338119a81c14SSteve Longerbeam /* Auto/manual exposure */ 338219a81c14SSteve Longerbeam ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, 338319a81c14SSteve Longerbeam V4L2_CID_EXPOSURE_AUTO, 338419a81c14SSteve Longerbeam V4L2_EXPOSURE_MANUAL, 0, 338519a81c14SSteve Longerbeam V4L2_EXPOSURE_AUTO); 338619a81c14SSteve Longerbeam ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 338719a81c14SSteve Longerbeam 0, 65535, 1, 0); 338819a81c14SSteve Longerbeam /* Auto/manual gain */ 338919a81c14SSteve Longerbeam ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 339019a81c14SSteve Longerbeam 0, 1, 1, 1); 339119a81c14SSteve Longerbeam ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 339219a81c14SSteve Longerbeam 0, 1023, 1, 0); 339319a81c14SSteve Longerbeam 339419a81c14SSteve Longerbeam ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 339519a81c14SSteve Longerbeam 0, 255, 1, 64); 339619a81c14SSteve Longerbeam ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, 339719a81c14SSteve Longerbeam 0, 359, 1, 0); 339819a81c14SSteve Longerbeam ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, 339919a81c14SSteve Longerbeam 0, 255, 1, 0); 340019a81c14SSteve Longerbeam ctrls->test_pattern = 340119a81c14SSteve Longerbeam v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, 340219a81c14SSteve Longerbeam ARRAY_SIZE(test_pattern_menu) - 1, 340319a81c14SSteve Longerbeam 0, 0, test_pattern_menu); 3404ce85705aSHugues Fruchet ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 3405ce85705aSHugues Fruchet 0, 1, 1, 0); 3406ce85705aSHugues Fruchet ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 3407ce85705aSHugues Fruchet 0, 1, 1, 0); 340819a81c14SSteve Longerbeam 34091068fecaSMylène Josserand ctrls->light_freq = 34101068fecaSMylène Josserand v4l2_ctrl_new_std_menu(hdl, ops, 34111068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY, 34121068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 34131068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_50HZ); 34141068fecaSMylène Josserand 341519a81c14SSteve Longerbeam if (hdl->error) { 341619a81c14SSteve Longerbeam ret = hdl->error; 341719a81c14SSteve Longerbeam goto free_ctrls; 341819a81c14SSteve Longerbeam } 341919a81c14SSteve Longerbeam 3420cc196e48SBenoit Parrot ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 34217a3b8d4bSJacopo Mondi ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 342219a81c14SSteve Longerbeam ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 342319a81c14SSteve Longerbeam ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; 342419a81c14SSteve Longerbeam 342519a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); 342619a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); 342719a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); 342819a81c14SSteve Longerbeam 342919a81c14SSteve Longerbeam sensor->sd.ctrl_handler = hdl; 343019a81c14SSteve Longerbeam return 0; 343119a81c14SSteve Longerbeam 343219a81c14SSteve Longerbeam free_ctrls: 343319a81c14SSteve Longerbeam v4l2_ctrl_handler_free(hdl); 343419a81c14SSteve Longerbeam return ret; 343519a81c14SSteve Longerbeam } 343619a81c14SSteve Longerbeam 343719a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd, 34380d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 343919a81c14SSteve Longerbeam struct v4l2_subdev_frame_size_enum *fse) 344019a81c14SSteve Longerbeam { 344119a81c14SSteve Longerbeam if (fse->pad != 0) 344219a81c14SSteve Longerbeam return -EINVAL; 344319a81c14SSteve Longerbeam if (fse->index >= OV5640_NUM_MODES) 344419a81c14SSteve Longerbeam return -EINVAL; 344519a81c14SSteve Longerbeam 3446*5113d5b3SJacopo Mondi fse->min_width = ov5640_mode_data[fse->index].width; 344741d8d7f5SHugues Fruchet fse->max_width = fse->min_width; 3448*5113d5b3SJacopo Mondi fse->min_height = ov5640_mode_data[fse->index].height; 344941d8d7f5SHugues Fruchet fse->max_height = fse->min_height; 345019a81c14SSteve Longerbeam 345119a81c14SSteve Longerbeam return 0; 345219a81c14SSteve Longerbeam } 345319a81c14SSteve Longerbeam 345419a81c14SSteve Longerbeam static int ov5640_enum_frame_interval( 345519a81c14SSteve Longerbeam struct v4l2_subdev *sd, 34560d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 345719a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval_enum *fie) 345819a81c14SSteve Longerbeam { 345919a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 346019a81c14SSteve Longerbeam struct v4l2_fract tpf; 346119a81c14SSteve Longerbeam int ret; 346219a81c14SSteve Longerbeam 346319a81c14SSteve Longerbeam if (fie->pad != 0) 346419a81c14SSteve Longerbeam return -EINVAL; 346519a81c14SSteve Longerbeam if (fie->index >= OV5640_NUM_FRAMERATES) 346619a81c14SSteve Longerbeam return -EINVAL; 346719a81c14SSteve Longerbeam 346819a81c14SSteve Longerbeam tpf.numerator = 1; 346919a81c14SSteve Longerbeam tpf.denominator = ov5640_framerates[fie->index]; 347019a81c14SSteve Longerbeam 347119a81c14SSteve Longerbeam ret = ov5640_try_frame_interval(sensor, &tpf, 347219a81c14SSteve Longerbeam fie->width, fie->height); 347319a81c14SSteve Longerbeam if (ret < 0) 347419a81c14SSteve Longerbeam return -EINVAL; 347519a81c14SSteve Longerbeam 347619a81c14SSteve Longerbeam fie->interval = tpf; 347719a81c14SSteve Longerbeam return 0; 347819a81c14SSteve Longerbeam } 347919a81c14SSteve Longerbeam 348019a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd, 348119a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 348219a81c14SSteve Longerbeam { 348319a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 348419a81c14SSteve Longerbeam 348519a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 348619a81c14SSteve Longerbeam fi->interval = sensor->frame_interval; 348719a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 348819a81c14SSteve Longerbeam 348919a81c14SSteve Longerbeam return 0; 349019a81c14SSteve Longerbeam } 349119a81c14SSteve Longerbeam 349219a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd, 349319a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 349419a81c14SSteve Longerbeam { 349519a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 349619a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 349719a81c14SSteve Longerbeam int frame_rate, ret = 0; 349819a81c14SSteve Longerbeam 349919a81c14SSteve Longerbeam if (fi->pad != 0) 350019a81c14SSteve Longerbeam return -EINVAL; 350119a81c14SSteve Longerbeam 350219a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 350319a81c14SSteve Longerbeam 350419a81c14SSteve Longerbeam if (sensor->streaming) { 350519a81c14SSteve Longerbeam ret = -EBUSY; 350619a81c14SSteve Longerbeam goto out; 350719a81c14SSteve Longerbeam } 350819a81c14SSteve Longerbeam 350919a81c14SSteve Longerbeam mode = sensor->current_mode; 351019a81c14SSteve Longerbeam 351119a81c14SSteve Longerbeam frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, 3512*5113d5b3SJacopo Mondi mode->width, 3513*5113d5b3SJacopo Mondi mode->height); 3514e823fb16SMaxime Ripard if (frame_rate < 0) { 3515e823fb16SMaxime Ripard /* Always return a valid frame interval value */ 3516e823fb16SMaxime Ripard fi->interval = sensor->frame_interval; 3517e823fb16SMaxime Ripard goto out; 3518e823fb16SMaxime Ripard } 351919a81c14SSteve Longerbeam 3520*5113d5b3SJacopo Mondi mode = ov5640_find_mode(sensor, frame_rate, mode->width, 3521*5113d5b3SJacopo Mondi mode->height, true); 35223c4a7372SHugues Fruchet if (!mode) { 35233c4a7372SHugues Fruchet ret = -EINVAL; 35243c4a7372SHugues Fruchet goto out; 35253c4a7372SHugues Fruchet } 35263c4a7372SHugues Fruchet 35270929983eSHugues Fruchet if (mode != sensor->current_mode || 35280929983eSHugues Fruchet frame_rate != sensor->current_fr) { 35290929983eSHugues Fruchet sensor->current_fr = frame_rate; 35300929983eSHugues Fruchet sensor->frame_interval = fi->interval; 35313c4a7372SHugues Fruchet sensor->current_mode = mode; 353219a81c14SSteve Longerbeam sensor->pending_mode_change = true; 3533cc196e48SBenoit Parrot 3534cc196e48SBenoit Parrot __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 3535cc196e48SBenoit Parrot ov5640_calc_pixel_rate(sensor)); 35366949d864SHugues Fruchet } 353719a81c14SSteve Longerbeam out: 353819a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 353919a81c14SSteve Longerbeam return ret; 354019a81c14SSteve Longerbeam } 354119a81c14SSteve Longerbeam 354219a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, 35430d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 354419a81c14SSteve Longerbeam struct v4l2_subdev_mbus_code_enum *code) 354519a81c14SSteve Longerbeam { 354619a81c14SSteve Longerbeam if (code->pad != 0) 354719a81c14SSteve Longerbeam return -EINVAL; 3548e3ee691dSHugues Fruchet if (code->index >= ARRAY_SIZE(ov5640_formats)) 354919a81c14SSteve Longerbeam return -EINVAL; 355019a81c14SSteve Longerbeam 3551e3ee691dSHugues Fruchet code->code = ov5640_formats[code->index].code; 355219a81c14SSteve Longerbeam return 0; 355319a81c14SSteve Longerbeam } 355419a81c14SSteve Longerbeam 355519a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) 355619a81c14SSteve Longerbeam { 355719a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 355819a81c14SSteve Longerbeam int ret = 0; 355919a81c14SSteve Longerbeam 356019a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 356119a81c14SSteve Longerbeam 356219a81c14SSteve Longerbeam if (sensor->streaming == !enable) { 356319a81c14SSteve Longerbeam if (enable && sensor->pending_mode_change) { 3564985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 356519a81c14SSteve Longerbeam if (ret) 356619a81c14SSteve Longerbeam goto out; 3567fb98e29fSHugues Fruchet } 3568e3ee691dSHugues Fruchet 3569fb98e29fSHugues Fruchet if (enable && sensor->pending_fmt_change) { 3570e3ee691dSHugues Fruchet ret = ov5640_set_framefmt(sensor, &sensor->fmt); 3571e3ee691dSHugues Fruchet if (ret) 3572e3ee691dSHugues Fruchet goto out; 3573fb98e29fSHugues Fruchet sensor->pending_fmt_change = false; 357419a81c14SSteve Longerbeam } 357519a81c14SSteve Longerbeam 35768e823f5cSJacopo Mondi if (ov5640_is_csi2(sensor)) 3577f22996dbSHugues Fruchet ret = ov5640_set_stream_mipi(sensor, enable); 3578f22996dbSHugues Fruchet else 3579f22996dbSHugues Fruchet ret = ov5640_set_stream_dvp(sensor, enable); 3580f22996dbSHugues Fruchet 358119a81c14SSteve Longerbeam if (!ret) 358219a81c14SSteve Longerbeam sensor->streaming = enable; 358319a81c14SSteve Longerbeam } 358419a81c14SSteve Longerbeam out: 358519a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 358619a81c14SSteve Longerbeam return ret; 358719a81c14SSteve Longerbeam } 358819a81c14SSteve Longerbeam 358919a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = { 359019a81c14SSteve Longerbeam .s_power = ov5640_s_power, 35912d18fbc5SAkinobu Mita .log_status = v4l2_ctrl_subdev_log_status, 35922d18fbc5SAkinobu Mita .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 35932d18fbc5SAkinobu Mita .unsubscribe_event = v4l2_event_subdev_unsubscribe, 359419a81c14SSteve Longerbeam }; 359519a81c14SSteve Longerbeam 359619a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = { 359719a81c14SSteve Longerbeam .g_frame_interval = ov5640_g_frame_interval, 359819a81c14SSteve Longerbeam .s_frame_interval = ov5640_s_frame_interval, 359919a81c14SSteve Longerbeam .s_stream = ov5640_s_stream, 360019a81c14SSteve Longerbeam }; 360119a81c14SSteve Longerbeam 360219a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { 360319a81c14SSteve Longerbeam .enum_mbus_code = ov5640_enum_mbus_code, 360419a81c14SSteve Longerbeam .get_fmt = ov5640_get_fmt, 360519a81c14SSteve Longerbeam .set_fmt = ov5640_set_fmt, 360619a81c14SSteve Longerbeam .enum_frame_size = ov5640_enum_frame_size, 360719a81c14SSteve Longerbeam .enum_frame_interval = ov5640_enum_frame_interval, 360819a81c14SSteve Longerbeam }; 360919a81c14SSteve Longerbeam 361019a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = { 361119a81c14SSteve Longerbeam .core = &ov5640_core_ops, 361219a81c14SSteve Longerbeam .video = &ov5640_video_ops, 361319a81c14SSteve Longerbeam .pad = &ov5640_pad_ops, 361419a81c14SSteve Longerbeam }; 361519a81c14SSteve Longerbeam 361619a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor) 361719a81c14SSteve Longerbeam { 361819a81c14SSteve Longerbeam int i; 361919a81c14SSteve Longerbeam 362019a81c14SSteve Longerbeam for (i = 0; i < OV5640_NUM_SUPPLIES; i++) 362119a81c14SSteve Longerbeam sensor->supplies[i].supply = ov5640_supply_name[i]; 362219a81c14SSteve Longerbeam 362319a81c14SSteve Longerbeam return devm_regulator_bulk_get(&sensor->i2c_client->dev, 362419a81c14SSteve Longerbeam OV5640_NUM_SUPPLIES, 362519a81c14SSteve Longerbeam sensor->supplies); 362619a81c14SSteve Longerbeam } 362719a81c14SSteve Longerbeam 36280f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor) 36290f7acb52SHugues Fruchet { 36300f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 36310f7acb52SHugues Fruchet int ret = 0; 36320f7acb52SHugues Fruchet u16 chip_id; 36330f7acb52SHugues Fruchet 36340f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 36350f7acb52SHugues Fruchet if (ret) 36360f7acb52SHugues Fruchet return ret; 36370f7acb52SHugues Fruchet 36380f7acb52SHugues Fruchet ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); 36390f7acb52SHugues Fruchet if (ret) { 36400f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to read chip identifier\n", 36410f7acb52SHugues Fruchet __func__); 36420f7acb52SHugues Fruchet goto power_off; 36430f7acb52SHugues Fruchet } 36440f7acb52SHugues Fruchet 36450f7acb52SHugues Fruchet if (chip_id != 0x5640) { 36460f7acb52SHugues Fruchet dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", 36470f7acb52SHugues Fruchet __func__, chip_id); 36480f7acb52SHugues Fruchet ret = -ENXIO; 36490f7acb52SHugues Fruchet } 36500f7acb52SHugues Fruchet 36510f7acb52SHugues Fruchet power_off: 36520f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 36530f7acb52SHugues Fruchet return ret; 36540f7acb52SHugues Fruchet } 36550f7acb52SHugues Fruchet 3656e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client) 365719a81c14SSteve Longerbeam { 365819a81c14SSteve Longerbeam struct device *dev = &client->dev; 365919a81c14SSteve Longerbeam struct fwnode_handle *endpoint; 366019a81c14SSteve Longerbeam struct ov5640_dev *sensor; 3661e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *fmt; 3662c3f3ba3eSHugues Fruchet u32 rotation; 366319a81c14SSteve Longerbeam int ret; 366419a81c14SSteve Longerbeam 366519a81c14SSteve Longerbeam sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 366619a81c14SSteve Longerbeam if (!sensor) 366719a81c14SSteve Longerbeam return -ENOMEM; 366819a81c14SSteve Longerbeam 366919a81c14SSteve Longerbeam sensor->i2c_client = client; 3670fb98e29fSHugues Fruchet 3671fb98e29fSHugues Fruchet /* 3672fb98e29fSHugues Fruchet * default init sequence initialize sensor to 3673fb98e29fSHugues Fruchet * YUV422 UYVY VGA@30fps 3674fb98e29fSHugues Fruchet */ 3675e6441fdeSHugues Fruchet fmt = &sensor->fmt; 3676fb98e29fSHugues Fruchet fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 3677fb98e29fSHugues Fruchet fmt->colorspace = V4L2_COLORSPACE_SRGB; 3678e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 3679e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 3680e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 3681e6441fdeSHugues Fruchet fmt->width = 640; 3682e6441fdeSHugues Fruchet fmt->height = 480; 3683e6441fdeSHugues Fruchet fmt->field = V4L2_FIELD_NONE; 368419a81c14SSteve Longerbeam sensor->frame_interval.numerator = 1; 368519a81c14SSteve Longerbeam sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; 368619a81c14SSteve Longerbeam sensor->current_fr = OV5640_30_FPS; 368719a81c14SSteve Longerbeam sensor->current_mode = 3688086c25f8SMaxime Ripard &ov5640_mode_data[OV5640_MODE_VGA_640_480]; 3689985cdcb0SHugues Fruchet sensor->last_mode = sensor->current_mode; 36903c28588fSJacopo Mondi sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ; 369119a81c14SSteve Longerbeam 369219a81c14SSteve Longerbeam sensor->ae_target = 52; 369319a81c14SSteve Longerbeam 3694c3f3ba3eSHugues Fruchet /* optional indication of physical rotation of sensor */ 3695c3f3ba3eSHugues Fruchet ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", 3696c3f3ba3eSHugues Fruchet &rotation); 3697c3f3ba3eSHugues Fruchet if (!ret) { 3698c3f3ba3eSHugues Fruchet switch (rotation) { 3699c3f3ba3eSHugues Fruchet case 180: 3700c3f3ba3eSHugues Fruchet sensor->upside_down = true; 37011771e9fbSGustavo A. R. Silva fallthrough; 3702c3f3ba3eSHugues Fruchet case 0: 3703c3f3ba3eSHugues Fruchet break; 3704c3f3ba3eSHugues Fruchet default: 3705c3f3ba3eSHugues Fruchet dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n", 3706c3f3ba3eSHugues Fruchet rotation); 3707c3f3ba3eSHugues Fruchet } 3708c3f3ba3eSHugues Fruchet } 3709c3f3ba3eSHugues Fruchet 3710ce96bcf5SSakari Ailus endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), 3711ce96bcf5SSakari Ailus NULL); 371219a81c14SSteve Longerbeam if (!endpoint) { 371319a81c14SSteve Longerbeam dev_err(dev, "endpoint node not found\n"); 371419a81c14SSteve Longerbeam return -EINVAL; 371519a81c14SSteve Longerbeam } 371619a81c14SSteve Longerbeam 371719a81c14SSteve Longerbeam ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep); 371819a81c14SSteve Longerbeam fwnode_handle_put(endpoint); 371919a81c14SSteve Longerbeam if (ret) { 372019a81c14SSteve Longerbeam dev_err(dev, "Could not parse endpoint\n"); 372119a81c14SSteve Longerbeam return ret; 372219a81c14SSteve Longerbeam } 372319a81c14SSteve Longerbeam 37242c61e48dSLad Prabhakar if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL && 37252c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY && 37262c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_BT656) { 37272c61e48dSLad Prabhakar dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type); 37282c61e48dSLad Prabhakar return -EINVAL; 37292c61e48dSLad Prabhakar } 37302c61e48dSLad Prabhakar 373119a81c14SSteve Longerbeam /* get system clock (xclk) */ 373219a81c14SSteve Longerbeam sensor->xclk = devm_clk_get(dev, "xclk"); 373319a81c14SSteve Longerbeam if (IS_ERR(sensor->xclk)) { 373419a81c14SSteve Longerbeam dev_err(dev, "failed to get xclk\n"); 373519a81c14SSteve Longerbeam return PTR_ERR(sensor->xclk); 373619a81c14SSteve Longerbeam } 373719a81c14SSteve Longerbeam 373819a81c14SSteve Longerbeam sensor->xclk_freq = clk_get_rate(sensor->xclk); 373919a81c14SSteve Longerbeam if (sensor->xclk_freq < OV5640_XCLK_MIN || 374019a81c14SSteve Longerbeam sensor->xclk_freq > OV5640_XCLK_MAX) { 374119a81c14SSteve Longerbeam dev_err(dev, "xclk frequency out of range: %d Hz\n", 374219a81c14SSteve Longerbeam sensor->xclk_freq); 374319a81c14SSteve Longerbeam return -EINVAL; 374419a81c14SSteve Longerbeam } 374519a81c14SSteve Longerbeam 374619a81c14SSteve Longerbeam /* request optional power down pin */ 374719a81c14SSteve Longerbeam sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", 374819a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 37498791a102SFabio Estevam if (IS_ERR(sensor->pwdn_gpio)) 37508791a102SFabio Estevam return PTR_ERR(sensor->pwdn_gpio); 37518791a102SFabio Estevam 375219a81c14SSteve Longerbeam /* request optional reset pin */ 375319a81c14SSteve Longerbeam sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", 375419a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 37558791a102SFabio Estevam if (IS_ERR(sensor->reset_gpio)) 37568791a102SFabio Estevam return PTR_ERR(sensor->reset_gpio); 375719a81c14SSteve Longerbeam 375819a81c14SSteve Longerbeam v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); 375919a81c14SSteve Longerbeam 37602d18fbc5SAkinobu Mita sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 37612d18fbc5SAkinobu Mita V4L2_SUBDEV_FL_HAS_EVENTS; 376219a81c14SSteve Longerbeam sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 376319a81c14SSteve Longerbeam sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 376419a81c14SSteve Longerbeam ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); 376519a81c14SSteve Longerbeam if (ret) 376619a81c14SSteve Longerbeam return ret; 376719a81c14SSteve Longerbeam 376819a81c14SSteve Longerbeam ret = ov5640_get_regulators(sensor); 376919a81c14SSteve Longerbeam if (ret) 377019a81c14SSteve Longerbeam return ret; 377119a81c14SSteve Longerbeam 377219a81c14SSteve Longerbeam mutex_init(&sensor->lock); 377319a81c14SSteve Longerbeam 37740f7acb52SHugues Fruchet ret = ov5640_check_chip_id(sensor); 37750f7acb52SHugues Fruchet if (ret) 37760f7acb52SHugues Fruchet goto entity_cleanup; 37770f7acb52SHugues Fruchet 377819a81c14SSteve Longerbeam ret = ov5640_init_controls(sensor); 377919a81c14SSteve Longerbeam if (ret) 378019a81c14SSteve Longerbeam goto entity_cleanup; 378119a81c14SSteve Longerbeam 378215786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(&sensor->sd); 378319a81c14SSteve Longerbeam if (ret) 378419a81c14SSteve Longerbeam goto free_ctrls; 378519a81c14SSteve Longerbeam 378619a81c14SSteve Longerbeam return 0; 378719a81c14SSteve Longerbeam 378819a81c14SSteve Longerbeam free_ctrls: 378919a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 379019a81c14SSteve Longerbeam entity_cleanup: 379119a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 3792bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 379319a81c14SSteve Longerbeam return ret; 379419a81c14SSteve Longerbeam } 379519a81c14SSteve Longerbeam 379619a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client) 379719a81c14SSteve Longerbeam { 379819a81c14SSteve Longerbeam struct v4l2_subdev *sd = i2c_get_clientdata(client); 379919a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 380019a81c14SSteve Longerbeam 380119a81c14SSteve Longerbeam v4l2_async_unregister_subdev(&sensor->sd); 380219a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 380319a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 3804bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 380519a81c14SSteve Longerbeam 380619a81c14SSteve Longerbeam return 0; 380719a81c14SSteve Longerbeam } 380819a81c14SSteve Longerbeam 380919a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = { 381019a81c14SSteve Longerbeam {"ov5640", 0}, 381119a81c14SSteve Longerbeam {}, 381219a81c14SSteve Longerbeam }; 381319a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id); 381419a81c14SSteve Longerbeam 381519a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = { 381619a81c14SSteve Longerbeam { .compatible = "ovti,ov5640" }, 381719a81c14SSteve Longerbeam { /* sentinel */ } 381819a81c14SSteve Longerbeam }; 381919a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids); 382019a81c14SSteve Longerbeam 382119a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = { 382219a81c14SSteve Longerbeam .driver = { 382319a81c14SSteve Longerbeam .name = "ov5640", 382419a81c14SSteve Longerbeam .of_match_table = ov5640_dt_ids, 382519a81c14SSteve Longerbeam }, 382619a81c14SSteve Longerbeam .id_table = ov5640_id, 3827e6714993SKieran Bingham .probe_new = ov5640_probe, 382819a81c14SSteve Longerbeam .remove = ov5640_remove, 382919a81c14SSteve Longerbeam }; 383019a81c14SSteve Longerbeam 383119a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver); 383219a81c14SSteve Longerbeam 383319a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver"); 383419a81c14SSteve Longerbeam MODULE_LICENSE("GPL"); 3835