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 325113d5b3SJacopo Mondi #define OV5640_NATIVE_WIDTH 2624 335113d5b3SJacopo Mondi #define OV5640_NATIVE_HEIGHT 1964 345113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_TOP 14 355113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_LEFT 16 365113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_WIDTH 2592 375113d5b3SJacopo Mondi #define OV5640_PIXEL_ARRAY_HEIGHT 1944 385113d5b3SJacopo Mondi 39*bce93b82SJacopo Mondi /* FIXME: not documented. */ 40*bce93b82SJacopo Mondi #define OV5640_MIN_VBLANK 24 41*bce93b82SJacopo Mondi #define OV5640_MAX_VTS 3375 42*bce93b82SJacopo Mondi 4319a81c14SSteve Longerbeam #define OV5640_DEFAULT_SLAVE_ID 0x3c 4419a81c14SSteve Longerbeam 453c28588fSJacopo Mondi #define OV5640_LINK_RATE_MAX 490000000U 463c28588fSJacopo Mondi 47d47c4126SHugues Fruchet #define OV5640_REG_SYS_RESET02 0x3002 48d47c4126SHugues Fruchet #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 49f22996dbSHugues Fruchet #define OV5640_REG_SYS_CTRL0 0x3008 503b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 513b987d70SLad Prabhakar #define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02 5219a81c14SSteve Longerbeam #define OV5640_REG_CHIP_ID 0x300a 53f22996dbSHugues Fruchet #define OV5640_REG_IO_MIPI_CTRL00 0x300e 54f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 55f22996dbSHugues Fruchet #define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 5619a81c14SSteve Longerbeam #define OV5640_REG_PAD_OUTPUT00 0x3019 57f22996dbSHugues Fruchet #define OV5640_REG_SYSTEM_CONTROL1 0x302e 5819a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL0 0x3034 5919a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL1 0x3035 6019a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL2 0x3036 6119a81c14SSteve Longerbeam #define OV5640_REG_SC_PLL_CTRL3 0x3037 6219a81c14SSteve Longerbeam #define OV5640_REG_SLAVE_ID 0x3100 63f22996dbSHugues Fruchet #define OV5640_REG_SCCB_SYS_CTRL1 0x3103 6419a81c14SSteve Longerbeam #define OV5640_REG_SYS_ROOT_DIVIDER 0x3108 6519a81c14SSteve Longerbeam #define OV5640_REG_AWB_R_GAIN 0x3400 6619a81c14SSteve Longerbeam #define OV5640_REG_AWB_G_GAIN 0x3402 6719a81c14SSteve Longerbeam #define OV5640_REG_AWB_B_GAIN 0x3404 6819a81c14SSteve Longerbeam #define OV5640_REG_AWB_MANUAL_CTRL 0x3406 6919a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_HI 0x3500 7019a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_MED 0x3501 7119a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_EXPOSURE_LO 0x3502 7219a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_MANUAL 0x3503 7319a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a 7419a81c14SSteve Longerbeam #define OV5640_REG_AEC_PK_VTS 0x350c 753145efcdSJacopo Mondi #define OV5640_REG_TIMING_HS 0x3800 763145efcdSJacopo Mondi #define OV5640_REG_TIMING_VS 0x3802 773145efcdSJacopo Mondi #define OV5640_REG_TIMING_HW 0x3804 783145efcdSJacopo Mondi #define OV5640_REG_TIMING_VH 0x3806 7986633417SMaxime Ripard #define OV5640_REG_TIMING_DVPHO 0x3808 8086633417SMaxime Ripard #define OV5640_REG_TIMING_DVPVO 0x380a 8119a81c14SSteve Longerbeam #define OV5640_REG_TIMING_HTS 0x380c 8219a81c14SSteve Longerbeam #define OV5640_REG_TIMING_VTS 0x380e 833145efcdSJacopo Mondi #define OV5640_REG_TIMING_HOFFS 0x3810 843145efcdSJacopo Mondi #define OV5640_REG_TIMING_VOFFS 0x3812 85ce85705aSHugues Fruchet #define OV5640_REG_TIMING_TC_REG20 0x3820 8619a81c14SSteve Longerbeam #define OV5640_REG_TIMING_TC_REG21 0x3821 8719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL00 0x3a00 8819a81c14SSteve Longerbeam #define OV5640_REG_AEC_B50_STEP 0x3a08 8919a81c14SSteve Longerbeam #define OV5640_REG_AEC_B60_STEP 0x3a0a 9019a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0D 0x3a0d 9119a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0E 0x3a0e 9219a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL0F 0x3a0f 9319a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL10 0x3a10 9419a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL11 0x3a11 9519a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1B 0x3a1b 9619a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1E 0x3a1e 9719a81c14SSteve Longerbeam #define OV5640_REG_AEC_CTRL1F 0x3a1f 9819a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL00 0x3c00 9919a81c14SSteve Longerbeam #define OV5640_REG_HZ5060_CTRL01 0x3c01 10019a81c14SSteve Longerbeam #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c 10119a81c14SSteve Longerbeam #define OV5640_REG_FRAME_CTRL01 0x4202 102e3ee691dSHugues Fruchet #define OV5640_REG_FORMAT_CONTROL00 0x4300 1037cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_HSIZE 0x4602 1047cb013b1SChen-Yu Tsai #define OV5640_REG_VFIFO_VSIZE 0x4604 1052b5c18f9SChen-Yu Tsai #define OV5640_REG_JPG_MODE_SELECT 0x4713 1064039b037SLad Prabhakar #define OV5640_REG_CCIR656_CTRL00 0x4730 107f22996dbSHugues Fruchet #define OV5640_REG_POLARITY_CTRL00 0x4740 10819a81c14SSteve Longerbeam #define OV5640_REG_MIPI_CTRL00 0x4800 10919a81c14SSteve Longerbeam #define OV5640_REG_DEBUG_MODE 0x4814 1106c957ed7SJacopo Mondi #define OV5640_REG_PCLK_PERIOD 0x4837 111e3ee691dSHugues Fruchet #define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f 11219a81c14SSteve Longerbeam #define OV5640_REG_PRE_ISP_TEST_SET1 0x503d 11319a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL0 0x5580 11419a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL1 0x5581 11519a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL3 0x5583 11619a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL4 0x5584 11719a81c14SSteve Longerbeam #define OV5640_REG_SDE_CTRL5 0x5585 11819a81c14SSteve Longerbeam #define OV5640_REG_AVG_READOUT 0x56a1 11919a81c14SSteve Longerbeam 12019a81c14SSteve Longerbeam enum ov5640_mode_id { 12132ea5e05SHugues Fruchet OV5640_MODE_QQVGA_160_120 = 0, 12232ea5e05SHugues Fruchet OV5640_MODE_QCIF_176_144, 12319a81c14SSteve Longerbeam OV5640_MODE_QVGA_320_240, 12419a81c14SSteve Longerbeam OV5640_MODE_VGA_640_480, 12519a81c14SSteve Longerbeam OV5640_MODE_NTSC_720_480, 12619a81c14SSteve Longerbeam OV5640_MODE_PAL_720_576, 12719a81c14SSteve Longerbeam OV5640_MODE_XGA_1024_768, 12819a81c14SSteve Longerbeam OV5640_MODE_720P_1280_720, 12919a81c14SSteve Longerbeam OV5640_MODE_1080P_1920_1080, 13019a81c14SSteve Longerbeam OV5640_MODE_QSXGA_2592_1944, 13119a81c14SSteve Longerbeam OV5640_NUM_MODES, 13219a81c14SSteve Longerbeam }; 13319a81c14SSteve Longerbeam 13419a81c14SSteve Longerbeam enum ov5640_frame_rate { 13519a81c14SSteve Longerbeam OV5640_15_FPS = 0, 13619a81c14SSteve Longerbeam OV5640_30_FPS, 137e823fb16SMaxime Ripard OV5640_60_FPS, 13819a81c14SSteve Longerbeam OV5640_NUM_FRAMERATES, 13919a81c14SSteve Longerbeam }; 14019a81c14SSteve Longerbeam 14122845bf2SJacopo Mondi enum ov5640_pixel_rate_id { 14222845bf2SJacopo Mondi OV5640_PIXEL_RATE_168M, 14322845bf2SJacopo Mondi OV5640_PIXEL_RATE_148M, 14422845bf2SJacopo Mondi OV5640_PIXEL_RATE_124M, 14522845bf2SJacopo Mondi OV5640_PIXEL_RATE_96M, 14622845bf2SJacopo Mondi OV5640_PIXEL_RATE_48M, 14722845bf2SJacopo Mondi OV5640_NUM_PIXEL_RATES, 14822845bf2SJacopo Mondi }; 14922845bf2SJacopo Mondi 15022845bf2SJacopo Mondi /* 15122845bf2SJacopo Mondi * The chip manual suggests 24/48/96/192 MHz pixel clocks. 15222845bf2SJacopo Mondi * 15322845bf2SJacopo Mondi * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for 15422845bf2SJacopo Mondi * full resolution mode @15 FPS. 15522845bf2SJacopo Mondi */ 15622845bf2SJacopo Mondi static const u32 ov5640_pixel_rates[] = { 15722845bf2SJacopo Mondi [OV5640_PIXEL_RATE_168M] = 168000000, 15822845bf2SJacopo Mondi [OV5640_PIXEL_RATE_148M] = 148000000, 15922845bf2SJacopo Mondi [OV5640_PIXEL_RATE_124M] = 124000000, 16022845bf2SJacopo Mondi [OV5640_PIXEL_RATE_96M] = 96000000, 16122845bf2SJacopo Mondi [OV5640_PIXEL_RATE_48M] = 48000000, 16222845bf2SJacopo Mondi }; 16322845bf2SJacopo Mondi 1647a3b8d4bSJacopo Mondi /* 1657a3b8d4bSJacopo Mondi * MIPI CSI-2 link frequencies. 1667a3b8d4bSJacopo Mondi * 1677a3b8d4bSJacopo Mondi * Derived from the above defined pixel rate for bpp = (8, 16, 24) and 1687a3b8d4bSJacopo Mondi * data_lanes = (1, 2) 1697a3b8d4bSJacopo Mondi * 1707a3b8d4bSJacopo Mondi * link_freq = (pixel_rate * bpp) / (2 * data_lanes) 1717a3b8d4bSJacopo Mondi */ 1727a3b8d4bSJacopo Mondi static const s64 ov5640_csi2_link_freqs[] = { 1737a3b8d4bSJacopo Mondi 992000000, 888000000, 768000000, 744000000, 672000000, 672000000, 1747a3b8d4bSJacopo Mondi 592000000, 592000000, 576000000, 576000000, 496000000, 496000000, 1757a3b8d4bSJacopo Mondi 384000000, 384000000, 384000000, 336000000, 296000000, 288000000, 1767a3b8d4bSJacopo Mondi 248000000, 192000000, 192000000, 192000000, 96000000, 1777a3b8d4bSJacopo Mondi }; 1787a3b8d4bSJacopo Mondi 1797a3b8d4bSJacopo Mondi /* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */ 1807a3b8d4bSJacopo Mondi #define OV5640_DEFAULT_LINK_FREQ 13 1817a3b8d4bSJacopo Mondi 182b7ed3abdSLoic Poulain enum ov5640_format_mux { 183b7ed3abdSLoic Poulain OV5640_FMT_MUX_YUV422 = 0, 184b7ed3abdSLoic Poulain OV5640_FMT_MUX_RGB, 185b7ed3abdSLoic Poulain OV5640_FMT_MUX_DITHER, 186b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_DPC, 187b7ed3abdSLoic Poulain OV5640_FMT_MUX_SNR_RAW, 188b7ed3abdSLoic Poulain OV5640_FMT_MUX_RAW_CIP, 189b7ed3abdSLoic Poulain }; 190b7ed3abdSLoic Poulain 1912d7671f6SJacopo Mondi static const struct ov5640_pixfmt { 192e3ee691dSHugues Fruchet u32 code; 193e3ee691dSHugues Fruchet u32 colorspace; 1942d7671f6SJacopo Mondi u8 bpp; 1952d7671f6SJacopo Mondi } ov5640_formats[] = { 1962d7671f6SJacopo Mondi { 1972d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_JPEG_1X8, 1982d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_JPEG, 1992d7671f6SJacopo Mondi .bpp = 16, 2002d7671f6SJacopo Mondi }, { 2012d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_2X8, 2022d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2032d7671f6SJacopo Mondi .bpp = 16, 2042d7671f6SJacopo Mondi }, { 2052d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_UYVY8_1X16, 2062d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2072d7671f6SJacopo Mondi .bpp = 16, 2082d7671f6SJacopo Mondi }, { 2092d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_2X8, 2102d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2112d7671f6SJacopo Mondi .bpp = 16, 2122d7671f6SJacopo Mondi }, { 2132d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_YUYV8_1X16, 2142d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2152d7671f6SJacopo Mondi .bpp = 16, 2162d7671f6SJacopo Mondi }, { 2172d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 2182d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2192d7671f6SJacopo Mondi .bpp = 16, 2202d7671f6SJacopo Mondi }, { 2212d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_RGB565_2X8_BE, 2222d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2232d7671f6SJacopo Mondi .bpp = 16, 2242d7671f6SJacopo Mondi }, { 2252d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SBGGR8_1X8, 2262d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2272d7671f6SJacopo Mondi .bpp = 8, 2282d7671f6SJacopo Mondi }, { 2292d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGBRG8_1X8, 2302d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2312d7671f6SJacopo Mondi .bpp = 8 2322d7671f6SJacopo Mondi }, { 2332d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SGRBG8_1X8, 2342d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2352d7671f6SJacopo Mondi .bpp = 8, 2362d7671f6SJacopo Mondi }, { 2372d7671f6SJacopo Mondi .code = MEDIA_BUS_FMT_SRGGB8_1X8, 2382d7671f6SJacopo Mondi .colorspace = V4L2_COLORSPACE_SRGB, 2392d7671f6SJacopo Mondi .bpp = 8, 2402d7671f6SJacopo Mondi }, 241e3ee691dSHugues Fruchet }; 242e3ee691dSHugues Fruchet 2433c28588fSJacopo Mondi static u32 ov5640_code_to_bpp(u32 code) 2443c28588fSJacopo Mondi { 2453c28588fSJacopo Mondi unsigned int i; 2463c28588fSJacopo Mondi 2473c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_formats); ++i) { 2483c28588fSJacopo Mondi if (ov5640_formats[i].code == code) 2493c28588fSJacopo Mondi return ov5640_formats[i].bpp; 2503c28588fSJacopo Mondi } 2513c28588fSJacopo Mondi 2523c28588fSJacopo Mondi return 0; 2533c28588fSJacopo Mondi } 2543c28588fSJacopo Mondi 25519a81c14SSteve Longerbeam /* 25619a81c14SSteve Longerbeam * FIXME: remove this when a subdev API becomes available 25719a81c14SSteve Longerbeam * to set the MIPI CSI-2 virtual channel. 25819a81c14SSteve Longerbeam */ 25919a81c14SSteve Longerbeam static unsigned int virtual_channel; 2608670d70aSHugues Fruchet module_param(virtual_channel, uint, 0444); 26119a81c14SSteve Longerbeam MODULE_PARM_DESC(virtual_channel, 26219a81c14SSteve Longerbeam "MIPI CSI-2 virtual channel (0..3), default 0"); 26319a81c14SSteve Longerbeam 26419a81c14SSteve Longerbeam static const int ov5640_framerates[] = { 26519a81c14SSteve Longerbeam [OV5640_15_FPS] = 15, 26619a81c14SSteve Longerbeam [OV5640_30_FPS] = 30, 267e823fb16SMaxime Ripard [OV5640_60_FPS] = 60, 26819a81c14SSteve Longerbeam }; 26919a81c14SSteve Longerbeam 27019a81c14SSteve Longerbeam /* regulator supplies */ 27119a81c14SSteve Longerbeam static const char * const ov5640_supply_name[] = { 27241d8d7f5SHugues Fruchet "DOVDD", /* Digital I/O (1.8V) supply */ 27319a81c14SSteve Longerbeam "AVDD", /* Analog (2.8V) supply */ 27424c8ac89SFabio Estevam "DVDD", /* Digital Core (1.5V) supply */ 27519a81c14SSteve Longerbeam }; 27619a81c14SSteve Longerbeam 27719a81c14SSteve Longerbeam #define OV5640_NUM_SUPPLIES ARRAY_SIZE(ov5640_supply_name) 27819a81c14SSteve Longerbeam 27919a81c14SSteve Longerbeam /* 28019a81c14SSteve Longerbeam * Image size under 1280 * 960 are SUBSAMPLING 28119a81c14SSteve Longerbeam * Image size upper 1280 * 960 are SCALING 28219a81c14SSteve Longerbeam */ 28319a81c14SSteve Longerbeam enum ov5640_downsize_mode { 28419a81c14SSteve Longerbeam SUBSAMPLING, 28519a81c14SSteve Longerbeam SCALING, 28619a81c14SSteve Longerbeam }; 28719a81c14SSteve Longerbeam 28819a81c14SSteve Longerbeam struct reg_value { 28919a81c14SSteve Longerbeam u16 reg_addr; 29019a81c14SSteve Longerbeam u8 val; 29119a81c14SSteve Longerbeam u8 mask; 29219a81c14SSteve Longerbeam u32 delay_ms; 29319a81c14SSteve Longerbeam }; 29419a81c14SSteve Longerbeam 2955113d5b3SJacopo Mondi struct ov5640_timings { 2963145efcdSJacopo Mondi /* Analog crop rectangle. */ 2973145efcdSJacopo Mondi struct v4l2_rect analog_crop; 2983145efcdSJacopo Mondi /* Visibile crop: from analog crop top-left corner. */ 2993145efcdSJacopo Mondi struct v4l2_rect crop; 3005113d5b3SJacopo Mondi /* Total pixels per line: width + fixed hblank. */ 301476dec01SMaxime Ripard u32 htot; 3025113d5b3SJacopo Mondi /* Default vertical blanking: frame height = height + vblank. */ 3033145efcdSJacopo Mondi u32 vblank_def; 3045113d5b3SJacopo Mondi }; 3055113d5b3SJacopo Mondi 3065113d5b3SJacopo Mondi struct ov5640_mode_info { 3075113d5b3SJacopo Mondi enum ov5640_mode_id id; 3085113d5b3SJacopo Mondi enum ov5640_downsize_mode dn_mode; 3095113d5b3SJacopo Mondi enum ov5640_pixel_rate_id pixel_rate; 3105113d5b3SJacopo Mondi 3115113d5b3SJacopo Mondi unsigned int width; 3125113d5b3SJacopo Mondi unsigned int height; 3135113d5b3SJacopo Mondi 3145113d5b3SJacopo Mondi struct ov5640_timings dvp_timings; 3155113d5b3SJacopo Mondi struct ov5640_timings csi2_timings; 3165113d5b3SJacopo Mondi 31719a81c14SSteve Longerbeam const struct reg_value *reg_data; 31819a81c14SSteve Longerbeam u32 reg_data_size; 3195113d5b3SJacopo Mondi 3205113d5b3SJacopo Mondi /* Used by s_frame_interval only. */ 3215554c80eSAdam Ford u32 max_fps; 32219a81c14SSteve Longerbeam }; 32319a81c14SSteve Longerbeam 32419a81c14SSteve Longerbeam struct ov5640_ctrls { 32519a81c14SSteve Longerbeam struct v4l2_ctrl_handler handler; 326cc196e48SBenoit Parrot struct v4l2_ctrl *pixel_rate; 3277a3b8d4bSJacopo Mondi struct v4l2_ctrl *link_freq; 32832979f67SJacopo Mondi struct v4l2_ctrl *hblank; 329*bce93b82SJacopo Mondi struct v4l2_ctrl *vblank; 33019a81c14SSteve Longerbeam struct { 33119a81c14SSteve Longerbeam struct v4l2_ctrl *auto_exp; 33219a81c14SSteve Longerbeam struct v4l2_ctrl *exposure; 33319a81c14SSteve Longerbeam }; 33419a81c14SSteve Longerbeam struct { 33519a81c14SSteve Longerbeam struct v4l2_ctrl *auto_wb; 33619a81c14SSteve Longerbeam struct v4l2_ctrl *blue_balance; 33719a81c14SSteve Longerbeam struct v4l2_ctrl *red_balance; 33819a81c14SSteve Longerbeam }; 33919a81c14SSteve Longerbeam struct { 34019a81c14SSteve Longerbeam struct v4l2_ctrl *auto_gain; 34119a81c14SSteve Longerbeam struct v4l2_ctrl *gain; 34219a81c14SSteve Longerbeam }; 34319a81c14SSteve Longerbeam struct v4l2_ctrl *brightness; 3441068fecaSMylène Josserand struct v4l2_ctrl *light_freq; 34519a81c14SSteve Longerbeam struct v4l2_ctrl *saturation; 34619a81c14SSteve Longerbeam struct v4l2_ctrl *contrast; 34719a81c14SSteve Longerbeam struct v4l2_ctrl *hue; 34819a81c14SSteve Longerbeam struct v4l2_ctrl *test_pattern; 349ce85705aSHugues Fruchet struct v4l2_ctrl *hflip; 350ce85705aSHugues Fruchet struct v4l2_ctrl *vflip; 35119a81c14SSteve Longerbeam }; 35219a81c14SSteve Longerbeam 35319a81c14SSteve Longerbeam struct ov5640_dev { 35419a81c14SSteve Longerbeam struct i2c_client *i2c_client; 35519a81c14SSteve Longerbeam struct v4l2_subdev sd; 35619a81c14SSteve Longerbeam struct media_pad pad; 35719a81c14SSteve Longerbeam struct v4l2_fwnode_endpoint ep; /* the parsed DT endpoint info */ 35819a81c14SSteve Longerbeam struct clk *xclk; /* system clock to OV5640 */ 35919a81c14SSteve Longerbeam u32 xclk_freq; 36019a81c14SSteve Longerbeam 36119a81c14SSteve Longerbeam struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES]; 36219a81c14SSteve Longerbeam struct gpio_desc *reset_gpio; 36319a81c14SSteve Longerbeam struct gpio_desc *pwdn_gpio; 364c3f3ba3eSHugues Fruchet bool upside_down; 36519a81c14SSteve Longerbeam 36619a81c14SSteve Longerbeam /* lock to protect all members below */ 36719a81c14SSteve Longerbeam struct mutex lock; 36819a81c14SSteve Longerbeam 36919a81c14SSteve Longerbeam int power_count; 37019a81c14SSteve Longerbeam 37119a81c14SSteve Longerbeam struct v4l2_mbus_framefmt fmt; 372fb98e29fSHugues Fruchet bool pending_fmt_change; 37319a81c14SSteve Longerbeam 37419a81c14SSteve Longerbeam const struct ov5640_mode_info *current_mode; 375985cdcb0SHugues Fruchet const struct ov5640_mode_info *last_mode; 37619a81c14SSteve Longerbeam enum ov5640_frame_rate current_fr; 37719a81c14SSteve Longerbeam struct v4l2_fract frame_interval; 3783c28588fSJacopo Mondi s64 current_link_freq; 37919a81c14SSteve Longerbeam 38019a81c14SSteve Longerbeam struct ov5640_ctrls ctrls; 38119a81c14SSteve Longerbeam 38219a81c14SSteve Longerbeam u32 prev_sysclk, prev_hts; 38319a81c14SSteve Longerbeam u32 ae_low, ae_high, ae_target; 38419a81c14SSteve Longerbeam 38519a81c14SSteve Longerbeam bool pending_mode_change; 38619a81c14SSteve Longerbeam bool streaming; 38719a81c14SSteve Longerbeam }; 38819a81c14SSteve Longerbeam 38919a81c14SSteve Longerbeam static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd) 39019a81c14SSteve Longerbeam { 39119a81c14SSteve Longerbeam return container_of(sd, struct ov5640_dev, sd); 39219a81c14SSteve Longerbeam } 39319a81c14SSteve Longerbeam 39419a81c14SSteve Longerbeam static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) 39519a81c14SSteve Longerbeam { 39619a81c14SSteve Longerbeam return &container_of(ctrl->handler, struct ov5640_dev, 39719a81c14SSteve Longerbeam ctrls.handler)->sd; 39819a81c14SSteve Longerbeam } 39919a81c14SSteve Longerbeam 4008e823f5cSJacopo Mondi static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor) 4018e823f5cSJacopo Mondi { 4028e823f5cSJacopo Mondi return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY; 4038e823f5cSJacopo Mondi } 4048e823f5cSJacopo Mondi 40519a81c14SSteve Longerbeam /* 40619a81c14SSteve Longerbeam * FIXME: all of these register tables are likely filled with 40719a81c14SSteve Longerbeam * entries that set the register to their power-on default values, 40819a81c14SSteve Longerbeam * and which are otherwise not touched by this driver. Those entries 40919a81c14SSteve Longerbeam * should be identified and removed to speed register load time 41019a81c14SSteve Longerbeam * over i2c. 41119a81c14SSteve Longerbeam */ 412fb98e29fSHugues Fruchet /* YUV422 UYVY VGA@30fps */ 413e4359019SJacopo Mondi static const struct reg_value ov5640_init_setting[] = { 41419a81c14SSteve Longerbeam {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, 415576f5d4bSLad Prabhakar {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0}, 41619a81c14SSteve Longerbeam {0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0}, 41719a81c14SSteve Longerbeam {0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0}, 41819a81c14SSteve Longerbeam {0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0}, 41919a81c14SSteve Longerbeam {0x3705, 0x1a, 0, 0}, {0x3905, 0x02, 0, 0}, {0x3906, 0x10, 0, 0}, 42019a81c14SSteve Longerbeam {0x3901, 0x0a, 0, 0}, {0x3731, 0x12, 0, 0}, {0x3600, 0x08, 0, 0}, 42119a81c14SSteve Longerbeam {0x3601, 0x33, 0, 0}, {0x302d, 0x60, 0, 0}, {0x3620, 0x52, 0, 0}, 42219a81c14SSteve Longerbeam {0x371b, 0x20, 0, 0}, {0x471c, 0x50, 0, 0}, {0x3a13, 0x43, 0, 0}, 42319a81c14SSteve Longerbeam {0x3a18, 0x00, 0, 0}, {0x3a19, 0xf8, 0, 0}, {0x3635, 0x13, 0, 0}, 42419a81c14SSteve Longerbeam {0x3636, 0x03, 0, 0}, {0x3634, 0x40, 0, 0}, {0x3622, 0x01, 0, 0}, 42519a81c14SSteve Longerbeam {0x3c01, 0xa4, 0, 0}, {0x3c04, 0x28, 0, 0}, {0x3c05, 0x98, 0, 0}, 42619a81c14SSteve Longerbeam {0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0}, 42719a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 42819a81c14SSteve Longerbeam {0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0}, 4293145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 43019a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 43119a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 43219a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 43319a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 43419a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 43519a81c14SSteve Longerbeam {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, 43619a81c14SSteve Longerbeam {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, 437aa4bb8b8SJacopo Mondi {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, 4382b5c18f9SChen-Yu Tsai {0x501f, 0x00, 0, 0}, {0x4407, 0x04, 0, 0}, 43919a81c14SSteve Longerbeam {0x440e, 0x00, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 440aa4bb8b8SJacopo Mondi {0x4837, 0x0a, 0, 0}, {0x3824, 0x02, 0, 0}, 44119a81c14SSteve Longerbeam {0x5000, 0xa7, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x5180, 0xff, 0, 0}, 44219a81c14SSteve Longerbeam {0x5181, 0xf2, 0, 0}, {0x5182, 0x00, 0, 0}, {0x5183, 0x14, 0, 0}, 44319a81c14SSteve Longerbeam {0x5184, 0x25, 0, 0}, {0x5185, 0x24, 0, 0}, {0x5186, 0x09, 0, 0}, 44419a81c14SSteve Longerbeam {0x5187, 0x09, 0, 0}, {0x5188, 0x09, 0, 0}, {0x5189, 0x88, 0, 0}, 44519a81c14SSteve Longerbeam {0x518a, 0x54, 0, 0}, {0x518b, 0xee, 0, 0}, {0x518c, 0xb2, 0, 0}, 44619a81c14SSteve Longerbeam {0x518d, 0x50, 0, 0}, {0x518e, 0x34, 0, 0}, {0x518f, 0x6b, 0, 0}, 44719a81c14SSteve Longerbeam {0x5190, 0x46, 0, 0}, {0x5191, 0xf8, 0, 0}, {0x5192, 0x04, 0, 0}, 44819a81c14SSteve Longerbeam {0x5193, 0x70, 0, 0}, {0x5194, 0xf0, 0, 0}, {0x5195, 0xf0, 0, 0}, 44919a81c14SSteve Longerbeam {0x5196, 0x03, 0, 0}, {0x5197, 0x01, 0, 0}, {0x5198, 0x04, 0, 0}, 45019a81c14SSteve Longerbeam {0x5199, 0x6c, 0, 0}, {0x519a, 0x04, 0, 0}, {0x519b, 0x00, 0, 0}, 45119a81c14SSteve Longerbeam {0x519c, 0x09, 0, 0}, {0x519d, 0x2b, 0, 0}, {0x519e, 0x38, 0, 0}, 45219a81c14SSteve Longerbeam {0x5381, 0x1e, 0, 0}, {0x5382, 0x5b, 0, 0}, {0x5383, 0x08, 0, 0}, 45319a81c14SSteve Longerbeam {0x5384, 0x0a, 0, 0}, {0x5385, 0x7e, 0, 0}, {0x5386, 0x88, 0, 0}, 45419a81c14SSteve Longerbeam {0x5387, 0x7c, 0, 0}, {0x5388, 0x6c, 0, 0}, {0x5389, 0x10, 0, 0}, 45519a81c14SSteve Longerbeam {0x538a, 0x01, 0, 0}, {0x538b, 0x98, 0, 0}, {0x5300, 0x08, 0, 0}, 45619a81c14SSteve Longerbeam {0x5301, 0x30, 0, 0}, {0x5302, 0x10, 0, 0}, {0x5303, 0x00, 0, 0}, 45719a81c14SSteve Longerbeam {0x5304, 0x08, 0, 0}, {0x5305, 0x30, 0, 0}, {0x5306, 0x08, 0, 0}, 45819a81c14SSteve Longerbeam {0x5307, 0x16, 0, 0}, {0x5309, 0x08, 0, 0}, {0x530a, 0x30, 0, 0}, 45919a81c14SSteve Longerbeam {0x530b, 0x04, 0, 0}, {0x530c, 0x06, 0, 0}, {0x5480, 0x01, 0, 0}, 46019a81c14SSteve Longerbeam {0x5481, 0x08, 0, 0}, {0x5482, 0x14, 0, 0}, {0x5483, 0x28, 0, 0}, 46119a81c14SSteve Longerbeam {0x5484, 0x51, 0, 0}, {0x5485, 0x65, 0, 0}, {0x5486, 0x71, 0, 0}, 46219a81c14SSteve Longerbeam {0x5487, 0x7d, 0, 0}, {0x5488, 0x87, 0, 0}, {0x5489, 0x91, 0, 0}, 46319a81c14SSteve Longerbeam {0x548a, 0x9a, 0, 0}, {0x548b, 0xaa, 0, 0}, {0x548c, 0xb8, 0, 0}, 46419a81c14SSteve Longerbeam {0x548d, 0xcd, 0, 0}, {0x548e, 0xdd, 0, 0}, {0x548f, 0xea, 0, 0}, 46519a81c14SSteve Longerbeam {0x5490, 0x1d, 0, 0}, {0x5580, 0x02, 0, 0}, {0x5583, 0x40, 0, 0}, 46619a81c14SSteve Longerbeam {0x5584, 0x10, 0, 0}, {0x5589, 0x10, 0, 0}, {0x558a, 0x00, 0, 0}, 46719a81c14SSteve Longerbeam {0x558b, 0xf8, 0, 0}, {0x5800, 0x23, 0, 0}, {0x5801, 0x14, 0, 0}, 46819a81c14SSteve Longerbeam {0x5802, 0x0f, 0, 0}, {0x5803, 0x0f, 0, 0}, {0x5804, 0x12, 0, 0}, 46919a81c14SSteve Longerbeam {0x5805, 0x26, 0, 0}, {0x5806, 0x0c, 0, 0}, {0x5807, 0x08, 0, 0}, 47019a81c14SSteve Longerbeam {0x5808, 0x05, 0, 0}, {0x5809, 0x05, 0, 0}, {0x580a, 0x08, 0, 0}, 47119a81c14SSteve Longerbeam {0x580b, 0x0d, 0, 0}, {0x580c, 0x08, 0, 0}, {0x580d, 0x03, 0, 0}, 47219a81c14SSteve Longerbeam {0x580e, 0x00, 0, 0}, {0x580f, 0x00, 0, 0}, {0x5810, 0x03, 0, 0}, 47319a81c14SSteve Longerbeam {0x5811, 0x09, 0, 0}, {0x5812, 0x07, 0, 0}, {0x5813, 0x03, 0, 0}, 47419a81c14SSteve Longerbeam {0x5814, 0x00, 0, 0}, {0x5815, 0x01, 0, 0}, {0x5816, 0x03, 0, 0}, 47519a81c14SSteve Longerbeam {0x5817, 0x08, 0, 0}, {0x5818, 0x0d, 0, 0}, {0x5819, 0x08, 0, 0}, 47619a81c14SSteve Longerbeam {0x581a, 0x05, 0, 0}, {0x581b, 0x06, 0, 0}, {0x581c, 0x08, 0, 0}, 47719a81c14SSteve Longerbeam {0x581d, 0x0e, 0, 0}, {0x581e, 0x29, 0, 0}, {0x581f, 0x17, 0, 0}, 47819a81c14SSteve Longerbeam {0x5820, 0x11, 0, 0}, {0x5821, 0x11, 0, 0}, {0x5822, 0x15, 0, 0}, 47919a81c14SSteve Longerbeam {0x5823, 0x28, 0, 0}, {0x5824, 0x46, 0, 0}, {0x5825, 0x26, 0, 0}, 48019a81c14SSteve Longerbeam {0x5826, 0x08, 0, 0}, {0x5827, 0x26, 0, 0}, {0x5828, 0x64, 0, 0}, 48119a81c14SSteve Longerbeam {0x5829, 0x26, 0, 0}, {0x582a, 0x24, 0, 0}, {0x582b, 0x22, 0, 0}, 48219a81c14SSteve Longerbeam {0x582c, 0x24, 0, 0}, {0x582d, 0x24, 0, 0}, {0x582e, 0x06, 0, 0}, 48319a81c14SSteve Longerbeam {0x582f, 0x22, 0, 0}, {0x5830, 0x40, 0, 0}, {0x5831, 0x42, 0, 0}, 48419a81c14SSteve Longerbeam {0x5832, 0x24, 0, 0}, {0x5833, 0x26, 0, 0}, {0x5834, 0x24, 0, 0}, 48519a81c14SSteve Longerbeam {0x5835, 0x22, 0, 0}, {0x5836, 0x22, 0, 0}, {0x5837, 0x26, 0, 0}, 48619a81c14SSteve Longerbeam {0x5838, 0x44, 0, 0}, {0x5839, 0x24, 0, 0}, {0x583a, 0x26, 0, 0}, 48719a81c14SSteve Longerbeam {0x583b, 0x28, 0, 0}, {0x583c, 0x42, 0, 0}, {0x583d, 0xce, 0, 0}, 48819a81c14SSteve Longerbeam {0x5025, 0x00, 0, 0}, {0x3a0f, 0x30, 0, 0}, {0x3a10, 0x28, 0, 0}, 48919a81c14SSteve Longerbeam {0x3a1b, 0x30, 0, 0}, {0x3a1e, 0x26, 0, 0}, {0x3a11, 0x60, 0, 0}, 49019a81c14SSteve Longerbeam {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, 49119a81c14SSteve Longerbeam }; 49219a81c14SSteve Longerbeam 493db15c195SJacopo Mondi static const struct reg_value ov5640_setting_low_res[] = { 494c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 49519a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 496ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 4973145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 49819a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 49919a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0}, 50019a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 50119a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 50219a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5032b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 504e15197bdSJacopo Mondi {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, 50519a81c14SSteve Longerbeam }; 50619a81c14SSteve Longerbeam 507086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_720P_1280_720[] = { 508c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, 50919a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 510ce85705aSHugues Fruchet {0x3814, 0x31, 0, 0}, 5113145efcdSJacopo Mondi {0x3815, 0x31, 0, 0}, 51219a81c14SSteve Longerbeam {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0}, 51319a81c14SSteve Longerbeam {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0}, 51419a81c14SSteve Longerbeam {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, 51519a81c14SSteve Longerbeam {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, 51619a81c14SSteve Longerbeam {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, 5172b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, 51819a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, 51919a81c14SSteve Longerbeam {0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, 52019a81c14SSteve Longerbeam }; 52119a81c14SSteve Longerbeam 522086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_1080P_1920_1080[] = { 523c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 52419a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 525ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 5263145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 52719a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 52819a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0}, 52919a81c14SSteve Longerbeam {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, 53019a81c14SSteve Longerbeam {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, 53119a81c14SSteve Longerbeam {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, 5322b5c18f9SChen-Yu Tsai {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, 53319a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 534c14d107eSMaxime Ripard {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, 535c14d107eSMaxime Ripard {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, 53619a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 537476dec01SMaxime Ripard {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, 53819a81c14SSteve Longerbeam {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, 53919a81c14SSteve Longerbeam {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, 54019a81c14SSteve Longerbeam {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, 5412b5c18f9SChen-Yu Tsai {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, 54219a81c14SSteve Longerbeam {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, 54392b9096cSBenoit Parrot {0x4005, 0x1a, 0, 0}, 54419a81c14SSteve Longerbeam }; 54519a81c14SSteve Longerbeam 546086c25f8SMaxime Ripard static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { 547c14d107eSMaxime Ripard {0x3c07, 0x08, 0, 0}, 54819a81c14SSteve Longerbeam {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, 549ce85705aSHugues Fruchet {0x3814, 0x11, 0, 0}, 5503145efcdSJacopo Mondi {0x3815, 0x11, 0, 0}, 55119a81c14SSteve Longerbeam {0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0}, 55219a81c14SSteve Longerbeam {0x3709, 0x12, 0, 0}, {0x370c, 0x00, 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, 0x06, 0, 0}, 55719a81c14SSteve Longerbeam {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, 55819a81c14SSteve Longerbeam {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, 55919a81c14SSteve Longerbeam }; 56019a81c14SSteve Longerbeam 5615113d5b3SJacopo Mondi static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = { 5628409d017SJacopo Mondi { 5638409d017SJacopo Mondi /* 160x120 */ 5643145efcdSJacopo Mondi .id = OV5640_MODE_QQVGA_160_120, 5653145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 5663145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 5675113d5b3SJacopo Mondi .width = 160, 5685113d5b3SJacopo Mondi .height = 120, 5695113d5b3SJacopo Mondi .dvp_timings = { 5703145efcdSJacopo Mondi .analog_crop = { 5713145efcdSJacopo Mondi .left = 0, 5723145efcdSJacopo Mondi .top = 4, 5733145efcdSJacopo Mondi .width = 2624, 5743145efcdSJacopo Mondi .height = 1944, 5753145efcdSJacopo Mondi }, 5763145efcdSJacopo Mondi .crop = { 5773145efcdSJacopo Mondi .left = 16, 5783145efcdSJacopo Mondi .top = 6, 5793145efcdSJacopo Mondi .width = 160, 5803145efcdSJacopo Mondi .height = 120, 5813145efcdSJacopo Mondi }, 5823145efcdSJacopo Mondi .htot = 1896, 5833145efcdSJacopo Mondi .vblank_def = 864, 5845113d5b3SJacopo Mondi }, 5855113d5b3SJacopo Mondi .csi2_timings = { 5865113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 5875113d5b3SJacopo Mondi .analog_crop = { 5885113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 5895113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 5905113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 5915113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 5925113d5b3SJacopo Mondi }, 5935113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 5945113d5b3SJacopo Mondi .crop = { 5955113d5b3SJacopo Mondi .left = 2, 5965113d5b3SJacopo Mondi .top = 4, 5975113d5b3SJacopo Mondi .width = 160, 5985113d5b3SJacopo Mondi .height = 120, 5995113d5b3SJacopo Mondi }, 6005113d5b3SJacopo Mondi .htot = 1896, 6015113d5b3SJacopo Mondi .vblank_def = 864, 6025113d5b3SJacopo Mondi }, 603db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 604db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 6053145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 6068409d017SJacopo Mondi }, { 6078409d017SJacopo Mondi /* 176x144 */ 6083145efcdSJacopo Mondi .id = OV5640_MODE_QCIF_176_144, 6093145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6103145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 6115113d5b3SJacopo Mondi .width = 176, 6125113d5b3SJacopo Mondi .height = 144, 6135113d5b3SJacopo Mondi .dvp_timings = { 6143145efcdSJacopo Mondi .analog_crop = { 6153145efcdSJacopo Mondi .left = 0, 6163145efcdSJacopo Mondi .top = 4, 6173145efcdSJacopo Mondi .width = 2624, 6183145efcdSJacopo Mondi .height = 1944, 6193145efcdSJacopo Mondi }, 6203145efcdSJacopo Mondi .crop = { 6213145efcdSJacopo Mondi .left = 16, 6223145efcdSJacopo Mondi .top = 6, 6233145efcdSJacopo Mondi .width = 176, 6243145efcdSJacopo Mondi .height = 144, 6253145efcdSJacopo Mondi }, 6263145efcdSJacopo Mondi .htot = 1896, 6273145efcdSJacopo Mondi .vblank_def = 840, 6285113d5b3SJacopo Mondi }, 6295113d5b3SJacopo Mondi .csi2_timings = { 6305113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 6315113d5b3SJacopo Mondi .analog_crop = { 6325113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 6335113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 6345113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 6355113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 6365113d5b3SJacopo Mondi }, 6375113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 6385113d5b3SJacopo Mondi .crop = { 6395113d5b3SJacopo Mondi .left = 2, 6405113d5b3SJacopo Mondi .top = 4, 6415113d5b3SJacopo Mondi .width = 176, 6425113d5b3SJacopo Mondi .height = 144, 6435113d5b3SJacopo Mondi }, 6445113d5b3SJacopo Mondi .htot = 1896, 6455113d5b3SJacopo Mondi .vblank_def = 840, 6465113d5b3SJacopo Mondi }, 647db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 648db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 6493145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 6508409d017SJacopo Mondi }, { 6518409d017SJacopo Mondi /* 320x240 */ 6523145efcdSJacopo Mondi .id = OV5640_MODE_QVGA_320_240, 6533145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6545113d5b3SJacopo Mondi .width = 320, 6555113d5b3SJacopo Mondi .height = 240, 6563145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 6575113d5b3SJacopo Mondi .dvp_timings = { 6583145efcdSJacopo Mondi .analog_crop = { 6593145efcdSJacopo Mondi .left = 0, 6603145efcdSJacopo Mondi .top = 4, 6613145efcdSJacopo Mondi .width = 2624, 6623145efcdSJacopo Mondi .height = 1944, 6633145efcdSJacopo Mondi }, 6643145efcdSJacopo Mondi .crop = { 6653145efcdSJacopo Mondi .left = 16, 6663145efcdSJacopo Mondi .top = 6, 6673145efcdSJacopo Mondi .width = 320, 6683145efcdSJacopo Mondi .height = 240, 6693145efcdSJacopo Mondi }, 6703145efcdSJacopo Mondi .htot = 1896, 6713145efcdSJacopo Mondi .vblank_def = 744, 6725113d5b3SJacopo Mondi }, 6735113d5b3SJacopo Mondi .csi2_timings = { 6745113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 6755113d5b3SJacopo Mondi .analog_crop = { 6765113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 6775113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 6785113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 6795113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 6805113d5b3SJacopo Mondi }, 6815113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 6825113d5b3SJacopo Mondi .crop = { 6835113d5b3SJacopo Mondi .left = 2, 6845113d5b3SJacopo Mondi .top = 4, 6855113d5b3SJacopo Mondi .width = 320, 6865113d5b3SJacopo Mondi .height = 240, 6875113d5b3SJacopo Mondi }, 6885113d5b3SJacopo Mondi .htot = 1896, 6895113d5b3SJacopo Mondi .vblank_def = 744, 6905113d5b3SJacopo Mondi }, 691db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 692db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 6933145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 6948409d017SJacopo Mondi }, { 6958409d017SJacopo Mondi /* 640x480 */ 6963145efcdSJacopo Mondi .id = OV5640_MODE_VGA_640_480, 6973145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 6983145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_48M, 6995113d5b3SJacopo Mondi .width = 640, 7005113d5b3SJacopo Mondi .height = 480, 7015113d5b3SJacopo Mondi .dvp_timings = { 7023145efcdSJacopo Mondi .analog_crop = { 7033145efcdSJacopo Mondi .left = 0, 7043145efcdSJacopo Mondi .top = 4, 7053145efcdSJacopo Mondi .width = 2624, 7063145efcdSJacopo Mondi .height = 1944, 7073145efcdSJacopo Mondi }, 7083145efcdSJacopo Mondi .crop = { 7093145efcdSJacopo Mondi .left = 16, 7103145efcdSJacopo Mondi .top = 6, 7113145efcdSJacopo Mondi .width = 640, 7123145efcdSJacopo Mondi .height = 480, 7133145efcdSJacopo Mondi }, 7143145efcdSJacopo Mondi .htot = 1896, 7153145efcdSJacopo Mondi .vblank_def = 600, 7165113d5b3SJacopo Mondi }, 7175113d5b3SJacopo Mondi .csi2_timings = { 7185113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 7195113d5b3SJacopo Mondi .analog_crop = { 7205113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 7215113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 7225113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 7235113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 7245113d5b3SJacopo Mondi }, 7255113d5b3SJacopo Mondi /* Maintain a minimum processing margin. */ 7265113d5b3SJacopo Mondi .crop = { 7275113d5b3SJacopo Mondi .left = 2, 7285113d5b3SJacopo Mondi .top = 4, 7295113d5b3SJacopo Mondi .width = 640, 7305113d5b3SJacopo Mondi .height = 480, 7315113d5b3SJacopo Mondi }, 7325113d5b3SJacopo Mondi .htot = 1896, 7335113d5b3SJacopo Mondi .vblank_def = 600, 7345113d5b3SJacopo Mondi }, 735db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 736db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 7373145efcdSJacopo Mondi .max_fps = OV5640_60_FPS 7388409d017SJacopo Mondi }, { 7398409d017SJacopo Mondi /* 720x480 */ 7403145efcdSJacopo Mondi .id = OV5640_MODE_NTSC_720_480, 7413145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7425113d5b3SJacopo Mondi .width = 720, 7435113d5b3SJacopo Mondi .height = 480, 7443145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 7455113d5b3SJacopo Mondi .dvp_timings = { 7463145efcdSJacopo Mondi .analog_crop = { 7473145efcdSJacopo Mondi .left = 0, 7483145efcdSJacopo Mondi .top = 4, 7493145efcdSJacopo Mondi .width = 2624, 7503145efcdSJacopo Mondi .height = 1944, 7513145efcdSJacopo Mondi }, 7523145efcdSJacopo Mondi .crop = { 753e74ef55bSJacopo Mondi .left = 56, 7543145efcdSJacopo Mondi .top = 60, 7553145efcdSJacopo Mondi .width = 720, 7563145efcdSJacopo Mondi .height = 480, 7573145efcdSJacopo Mondi }, 7583145efcdSJacopo Mondi .htot = 1896, 7593145efcdSJacopo Mondi .vblank_def = 504, 7605113d5b3SJacopo Mondi }, 7615113d5b3SJacopo Mondi .csi2_timings = { 7625113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 7635113d5b3SJacopo Mondi .analog_crop = { 7645113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 7655113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 7665113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 7675113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 7685113d5b3SJacopo Mondi }, 7695113d5b3SJacopo Mondi .crop = { 7705113d5b3SJacopo Mondi .left = 56, 7715113d5b3SJacopo Mondi .top = 60, 7725113d5b3SJacopo Mondi .width = 720, 7735113d5b3SJacopo Mondi .height = 480, 7745113d5b3SJacopo Mondi }, 7755113d5b3SJacopo Mondi .htot = 1896, 7765113d5b3SJacopo Mondi .vblank_def = 504, 7775113d5b3SJacopo Mondi }, 778db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 779db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 7803145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 7818409d017SJacopo Mondi }, { 7828409d017SJacopo Mondi /* 720x576 */ 7833145efcdSJacopo Mondi .id = OV5640_MODE_PAL_720_576, 7843145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 7855113d5b3SJacopo Mondi .width = 720, 7865113d5b3SJacopo Mondi .height = 576, 7873145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 7885113d5b3SJacopo Mondi .dvp_timings = { 7893145efcdSJacopo Mondi .analog_crop = { 7903145efcdSJacopo Mondi .left = 0, 7913145efcdSJacopo Mondi .top = 4, 7923145efcdSJacopo Mondi .width = 2624, 7933145efcdSJacopo Mondi .height = 1944, 7943145efcdSJacopo Mondi }, 7953145efcdSJacopo Mondi .crop = { 7963145efcdSJacopo Mondi .left = 56, 7973145efcdSJacopo Mondi .top = 6, 7983145efcdSJacopo Mondi .width = 720, 7993145efcdSJacopo Mondi .height = 576, 8003145efcdSJacopo Mondi }, 8013145efcdSJacopo Mondi .htot = 1896, 8023145efcdSJacopo Mondi .vblank_def = 408, 8035113d5b3SJacopo Mondi }, 8045113d5b3SJacopo Mondi .csi2_timings = { 8055113d5b3SJacopo Mondi /* Feed the full valid pixel array to the ISP. */ 8065113d5b3SJacopo Mondi .analog_crop = { 8075113d5b3SJacopo Mondi .left = OV5640_PIXEL_ARRAY_LEFT, 8085113d5b3SJacopo Mondi .top = OV5640_PIXEL_ARRAY_TOP, 8095113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 8105113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 8115113d5b3SJacopo Mondi }, 8125113d5b3SJacopo Mondi .crop = { 8135113d5b3SJacopo Mondi .left = 56, 8145113d5b3SJacopo Mondi .top = 6, 8155113d5b3SJacopo Mondi .width = 720, 8165113d5b3SJacopo Mondi .height = 576, 8175113d5b3SJacopo Mondi }, 8185113d5b3SJacopo Mondi .htot = 1896, 8195113d5b3SJacopo Mondi .vblank_def = 408, 8205113d5b3SJacopo Mondi }, 821db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 822db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 8233145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 8248409d017SJacopo Mondi }, { 8258409d017SJacopo Mondi /* 1024x768 */ 8263145efcdSJacopo Mondi .id = OV5640_MODE_XGA_1024_768, 8273145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 8283145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_96M, 8295113d5b3SJacopo Mondi .width = 1024, 8305113d5b3SJacopo Mondi .height = 768, 8315113d5b3SJacopo Mondi .dvp_timings = { 8323145efcdSJacopo Mondi .analog_crop = { 8333145efcdSJacopo Mondi .left = 0, 8343145efcdSJacopo Mondi .top = 4, 8353145efcdSJacopo Mondi .width = 2624, 8363145efcdSJacopo Mondi .height = 1944, 8373145efcdSJacopo Mondi }, 8383145efcdSJacopo Mondi .crop = { 8393145efcdSJacopo Mondi .left = 16, 8403145efcdSJacopo Mondi .top = 6, 8413145efcdSJacopo Mondi .width = 1024, 8423145efcdSJacopo Mondi .height = 768, 8433145efcdSJacopo Mondi }, 8443145efcdSJacopo Mondi .htot = 1896, 8453145efcdSJacopo Mondi .vblank_def = 312, 8465113d5b3SJacopo Mondi }, 8475113d5b3SJacopo Mondi .csi2_timings = { 8485113d5b3SJacopo Mondi .analog_crop = { 8495113d5b3SJacopo Mondi .left = 0, 8505113d5b3SJacopo Mondi .top = 4, 8515113d5b3SJacopo Mondi .width = OV5640_NATIVE_WIDTH, 8525113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 8535113d5b3SJacopo Mondi }, 8545113d5b3SJacopo Mondi .crop = { 8555113d5b3SJacopo Mondi .left = 16, 8565113d5b3SJacopo Mondi .top = 6, 8575113d5b3SJacopo Mondi .width = 1024, 8585113d5b3SJacopo Mondi .height = 768, 8595113d5b3SJacopo Mondi }, 8605113d5b3SJacopo Mondi .htot = 1896, 8615113d5b3SJacopo Mondi .vblank_def = 312, 8625113d5b3SJacopo Mondi }, 863db15c195SJacopo Mondi .reg_data = ov5640_setting_low_res, 864db15c195SJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res), 8653145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 8668409d017SJacopo Mondi }, { 8678409d017SJacopo Mondi /* 1280x720 */ 8683145efcdSJacopo Mondi .id = OV5640_MODE_720P_1280_720, 8693145efcdSJacopo Mondi .dn_mode = SUBSAMPLING, 8703145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_124M, 8715113d5b3SJacopo Mondi .width = 1280, 8725113d5b3SJacopo Mondi .height = 720, 8735113d5b3SJacopo Mondi .dvp_timings = { 8743145efcdSJacopo Mondi .analog_crop = { 8753145efcdSJacopo Mondi .left = 0, 8763145efcdSJacopo Mondi .top = 250, 8773145efcdSJacopo Mondi .width = 2624, 8783145efcdSJacopo Mondi .height = 1456, 8793145efcdSJacopo Mondi }, 8803145efcdSJacopo Mondi .crop = { 8813145efcdSJacopo Mondi .left = 16, 8823145efcdSJacopo Mondi .top = 4, 8833145efcdSJacopo Mondi .width = 1280, 8843145efcdSJacopo Mondi .height = 720, 8853145efcdSJacopo Mondi }, 8863145efcdSJacopo Mondi .htot = 1892, 8873145efcdSJacopo Mondi .vblank_def = 20, 8885113d5b3SJacopo Mondi }, 8895113d5b3SJacopo Mondi .csi2_timings = { 8905113d5b3SJacopo Mondi .analog_crop = { 8915113d5b3SJacopo Mondi .left = 0, 8925113d5b3SJacopo Mondi .top = 250, 8935113d5b3SJacopo Mondi .width = 2624, 8945113d5b3SJacopo Mondi .height = 1456, 8955113d5b3SJacopo Mondi }, 8965113d5b3SJacopo Mondi .crop = { 8975113d5b3SJacopo Mondi .left = 16, 8985113d5b3SJacopo Mondi .top = 4, 8995113d5b3SJacopo Mondi .width = 1280, 9005113d5b3SJacopo Mondi .height = 720, 9015113d5b3SJacopo Mondi }, 9025113d5b3SJacopo Mondi .htot = 1892, 9035113d5b3SJacopo Mondi .vblank_def = 20, 9045113d5b3SJacopo Mondi }, 9053145efcdSJacopo Mondi .reg_data = ov5640_setting_720P_1280_720, 9063145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720), 9073145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 9088409d017SJacopo Mondi }, { 9098409d017SJacopo Mondi /* 1920x1080 */ 9103145efcdSJacopo Mondi .id = OV5640_MODE_1080P_1920_1080, 9113145efcdSJacopo Mondi .dn_mode = SCALING, 9123145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_148M, 9135113d5b3SJacopo Mondi .width = 1920, 9145113d5b3SJacopo Mondi .height = 1080, 9155113d5b3SJacopo Mondi .dvp_timings = { 9163145efcdSJacopo Mondi .analog_crop = { 9173145efcdSJacopo Mondi .left = 336, 9183145efcdSJacopo Mondi .top = 434, 9193145efcdSJacopo Mondi .width = 1952, 9203145efcdSJacopo Mondi .height = 1088, 9213145efcdSJacopo Mondi }, 9223145efcdSJacopo Mondi .crop = { 9233145efcdSJacopo Mondi .left = 16, 9243145efcdSJacopo Mondi .top = 4, 9253145efcdSJacopo Mondi .width = 1920, 9263145efcdSJacopo Mondi .height = 1080, 9273145efcdSJacopo Mondi }, 9283145efcdSJacopo Mondi .htot = 2500, 9293145efcdSJacopo Mondi .vblank_def = 40, 9305113d5b3SJacopo Mondi }, 9315113d5b3SJacopo Mondi .csi2_timings = { 9325113d5b3SJacopo Mondi /* Crop the full valid pixel array in the center. */ 9335113d5b3SJacopo Mondi .analog_crop = { 9345113d5b3SJacopo Mondi .left = 336, 9355113d5b3SJacopo Mondi .top = 434, 9365113d5b3SJacopo Mondi .width = 1952, 9375113d5b3SJacopo Mondi .height = 1088, 9385113d5b3SJacopo Mondi }, 9395113d5b3SJacopo Mondi /* Maintain a larger processing margins. */ 9405113d5b3SJacopo Mondi .crop = { 9415113d5b3SJacopo Mondi .left = 16, 9425113d5b3SJacopo Mondi .top = 4, 9435113d5b3SJacopo Mondi .width = 1920, 9445113d5b3SJacopo Mondi .height = 1080, 9455113d5b3SJacopo Mondi }, 9465113d5b3SJacopo Mondi .htot = 2500, 9475113d5b3SJacopo Mondi .vblank_def = 40, 9485113d5b3SJacopo Mondi }, 9493145efcdSJacopo Mondi .reg_data = ov5640_setting_1080P_1920_1080, 9503145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080), 9513145efcdSJacopo Mondi .max_fps = OV5640_30_FPS 9528409d017SJacopo Mondi }, { 9538409d017SJacopo Mondi /* 2592x1944 */ 9543145efcdSJacopo Mondi .id = OV5640_MODE_QSXGA_2592_1944, 9553145efcdSJacopo Mondi .dn_mode = SCALING, 9563145efcdSJacopo Mondi .pixel_rate = OV5640_PIXEL_RATE_168M, 9575113d5b3SJacopo Mondi .width = OV5640_PIXEL_ARRAY_WIDTH, 9585113d5b3SJacopo Mondi .height = OV5640_PIXEL_ARRAY_HEIGHT, 9595113d5b3SJacopo Mondi .dvp_timings = { 9603145efcdSJacopo Mondi .analog_crop = { 9613145efcdSJacopo Mondi .left = 0, 9623145efcdSJacopo Mondi .top = 0, 9633145efcdSJacopo Mondi .width = 2624, 9643145efcdSJacopo Mondi .height = 1952, 9653145efcdSJacopo Mondi }, 9663145efcdSJacopo Mondi .crop = { 9673145efcdSJacopo Mondi .left = 16, 9683145efcdSJacopo Mondi .top = 4, 9693145efcdSJacopo Mondi .width = 2592, 9703145efcdSJacopo Mondi .height = 1944, 9713145efcdSJacopo Mondi }, 9723145efcdSJacopo Mondi .htot = 2844, 9733145efcdSJacopo Mondi .vblank_def = 24, 9745113d5b3SJacopo Mondi }, 9755113d5b3SJacopo Mondi .csi2_timings = { 9765113d5b3SJacopo Mondi /* Give more processing margin to full resolution. */ 9775113d5b3SJacopo Mondi .analog_crop = { 9785113d5b3SJacopo Mondi .left = 0, 9795113d5b3SJacopo Mondi .top = 0, 9805113d5b3SJacopo Mondi .width = OV5640_NATIVE_WIDTH, 9815113d5b3SJacopo Mondi .height = 1952, 9825113d5b3SJacopo Mondi }, 9835113d5b3SJacopo Mondi .crop = { 9845113d5b3SJacopo Mondi .left = 16, 9855113d5b3SJacopo Mondi .top = 4, 9865113d5b3SJacopo Mondi .width = 2592, 9875113d5b3SJacopo Mondi .height = 1944, 9885113d5b3SJacopo Mondi }, 9895113d5b3SJacopo Mondi .htot = 2844, 9905113d5b3SJacopo Mondi .vblank_def = 24, 9915113d5b3SJacopo Mondi }, 9923145efcdSJacopo Mondi .reg_data = ov5640_setting_QSXGA_2592_1944, 9933145efcdSJacopo Mondi .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944), 9943145efcdSJacopo Mondi .max_fps = OV5640_15_FPS 9958409d017SJacopo Mondi }, 99619a81c14SSteve Longerbeam }; 99719a81c14SSteve Longerbeam 9982de6bb97SJacopo Mondi static const struct ov5640_timings * 9992de6bb97SJacopo Mondi ov5640_timings(const struct ov5640_dev *sensor, 10002de6bb97SJacopo Mondi const struct ov5640_mode_info *mode) 10012de6bb97SJacopo Mondi { 10022de6bb97SJacopo Mondi if (ov5640_is_csi2(sensor)) 10032de6bb97SJacopo Mondi return &mode->csi2_timings; 10042de6bb97SJacopo Mondi 10052de6bb97SJacopo Mondi return &mode->dvp_timings; 10062de6bb97SJacopo Mondi } 10072de6bb97SJacopo Mondi 100819a81c14SSteve Longerbeam static int ov5640_init_slave_id(struct ov5640_dev *sensor) 100919a81c14SSteve Longerbeam { 101019a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 101119a81c14SSteve Longerbeam struct i2c_msg msg; 101219a81c14SSteve Longerbeam u8 buf[3]; 101319a81c14SSteve Longerbeam int ret; 101419a81c14SSteve Longerbeam 101519a81c14SSteve Longerbeam if (client->addr == OV5640_DEFAULT_SLAVE_ID) 101619a81c14SSteve Longerbeam return 0; 101719a81c14SSteve Longerbeam 101819a81c14SSteve Longerbeam buf[0] = OV5640_REG_SLAVE_ID >> 8; 101919a81c14SSteve Longerbeam buf[1] = OV5640_REG_SLAVE_ID & 0xff; 102019a81c14SSteve Longerbeam buf[2] = client->addr << 1; 102119a81c14SSteve Longerbeam 102219a81c14SSteve Longerbeam msg.addr = OV5640_DEFAULT_SLAVE_ID; 102319a81c14SSteve Longerbeam msg.flags = 0; 102419a81c14SSteve Longerbeam msg.buf = buf; 102519a81c14SSteve Longerbeam msg.len = sizeof(buf); 102619a81c14SSteve Longerbeam 102719a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 102819a81c14SSteve Longerbeam if (ret < 0) { 102919a81c14SSteve Longerbeam dev_err(&client->dev, "%s: failed with %d\n", __func__, ret); 103019a81c14SSteve Longerbeam return ret; 103119a81c14SSteve Longerbeam } 103219a81c14SSteve Longerbeam 103319a81c14SSteve Longerbeam return 0; 103419a81c14SSteve Longerbeam } 103519a81c14SSteve Longerbeam 103619a81c14SSteve Longerbeam static int ov5640_write_reg(struct ov5640_dev *sensor, u16 reg, u8 val) 103719a81c14SSteve Longerbeam { 103819a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 103919a81c14SSteve Longerbeam struct i2c_msg msg; 104019a81c14SSteve Longerbeam u8 buf[3]; 104119a81c14SSteve Longerbeam int ret; 104219a81c14SSteve Longerbeam 104319a81c14SSteve Longerbeam buf[0] = reg >> 8; 104419a81c14SSteve Longerbeam buf[1] = reg & 0xff; 104519a81c14SSteve Longerbeam buf[2] = val; 104619a81c14SSteve Longerbeam 104719a81c14SSteve Longerbeam msg.addr = client->addr; 104819a81c14SSteve Longerbeam msg.flags = client->flags; 104919a81c14SSteve Longerbeam msg.buf = buf; 105019a81c14SSteve Longerbeam msg.len = sizeof(buf); 105119a81c14SSteve Longerbeam 105219a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, &msg, 1); 105319a81c14SSteve Longerbeam if (ret < 0) { 10543924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x, val=%x\n", 105519a81c14SSteve Longerbeam __func__, reg, val); 105619a81c14SSteve Longerbeam return ret; 105719a81c14SSteve Longerbeam } 105819a81c14SSteve Longerbeam 105919a81c14SSteve Longerbeam return 0; 106019a81c14SSteve Longerbeam } 106119a81c14SSteve Longerbeam 106219a81c14SSteve Longerbeam static int ov5640_read_reg(struct ov5640_dev *sensor, u16 reg, u8 *val) 106319a81c14SSteve Longerbeam { 106419a81c14SSteve Longerbeam struct i2c_client *client = sensor->i2c_client; 106519a81c14SSteve Longerbeam struct i2c_msg msg[2]; 106619a81c14SSteve Longerbeam u8 buf[2]; 106719a81c14SSteve Longerbeam int ret; 106819a81c14SSteve Longerbeam 106919a81c14SSteve Longerbeam buf[0] = reg >> 8; 107019a81c14SSteve Longerbeam buf[1] = reg & 0xff; 107119a81c14SSteve Longerbeam 107219a81c14SSteve Longerbeam msg[0].addr = client->addr; 107319a81c14SSteve Longerbeam msg[0].flags = client->flags; 107419a81c14SSteve Longerbeam msg[0].buf = buf; 107519a81c14SSteve Longerbeam msg[0].len = sizeof(buf); 107619a81c14SSteve Longerbeam 107719a81c14SSteve Longerbeam msg[1].addr = client->addr; 107819a81c14SSteve Longerbeam msg[1].flags = client->flags | I2C_M_RD; 107919a81c14SSteve Longerbeam msg[1].buf = buf; 108019a81c14SSteve Longerbeam msg[1].len = 1; 108119a81c14SSteve Longerbeam 108219a81c14SSteve Longerbeam ret = i2c_transfer(client->adapter, msg, 2); 10833924c623SHugues Fruchet if (ret < 0) { 10843924c623SHugues Fruchet dev_err(&client->dev, "%s: error: reg=%x\n", 10853924c623SHugues Fruchet __func__, reg); 108619a81c14SSteve Longerbeam return ret; 10873924c623SHugues Fruchet } 108819a81c14SSteve Longerbeam 108919a81c14SSteve Longerbeam *val = buf[0]; 109019a81c14SSteve Longerbeam return 0; 109119a81c14SSteve Longerbeam } 109219a81c14SSteve Longerbeam 109319a81c14SSteve Longerbeam static int ov5640_read_reg16(struct ov5640_dev *sensor, u16 reg, u16 *val) 109419a81c14SSteve Longerbeam { 109519a81c14SSteve Longerbeam u8 hi, lo; 109619a81c14SSteve Longerbeam int ret; 109719a81c14SSteve Longerbeam 109819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &hi); 109919a81c14SSteve Longerbeam if (ret) 110019a81c14SSteve Longerbeam return ret; 110119a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg + 1, &lo); 110219a81c14SSteve Longerbeam if (ret) 110319a81c14SSteve Longerbeam return ret; 110419a81c14SSteve Longerbeam 110519a81c14SSteve Longerbeam *val = ((u16)hi << 8) | (u16)lo; 110619a81c14SSteve Longerbeam return 0; 110719a81c14SSteve Longerbeam } 110819a81c14SSteve Longerbeam 110919a81c14SSteve Longerbeam static int ov5640_write_reg16(struct ov5640_dev *sensor, u16 reg, u16 val) 111019a81c14SSteve Longerbeam { 111119a81c14SSteve Longerbeam int ret; 111219a81c14SSteve Longerbeam 111319a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg, val >> 8); 111419a81c14SSteve Longerbeam if (ret) 111519a81c14SSteve Longerbeam return ret; 111619a81c14SSteve Longerbeam 111719a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg + 1, val & 0xff); 111819a81c14SSteve Longerbeam } 111919a81c14SSteve Longerbeam 112019a81c14SSteve Longerbeam static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, 112119a81c14SSteve Longerbeam u8 mask, u8 val) 112219a81c14SSteve Longerbeam { 112319a81c14SSteve Longerbeam u8 readval; 112419a81c14SSteve Longerbeam int ret; 112519a81c14SSteve Longerbeam 112619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, reg, &readval); 112719a81c14SSteve Longerbeam if (ret) 112819a81c14SSteve Longerbeam return ret; 112919a81c14SSteve Longerbeam 113019a81c14SSteve Longerbeam readval &= ~mask; 113119a81c14SSteve Longerbeam val &= mask; 113219a81c14SSteve Longerbeam val |= readval; 113319a81c14SSteve Longerbeam 113419a81c14SSteve Longerbeam return ov5640_write_reg(sensor, reg, val); 113519a81c14SSteve Longerbeam } 113619a81c14SSteve Longerbeam 1137aa288248SMaxime Ripard /* 1138aa288248SMaxime Ripard * After trying the various combinations, reading various 1139f8a7647dSMauro Carvalho Chehab * documentations spread around the net, and from the various 1140aa288248SMaxime Ripard * feedback, the clock tree is probably as follows: 1141aa288248SMaxime Ripard * 1142aa288248SMaxime Ripard * +--------------+ 1143aa288248SMaxime Ripard * | Ext. Clock | 1144aa288248SMaxime Ripard * +-+------------+ 1145aa288248SMaxime Ripard * | +----------+ 1146aa288248SMaxime Ripard * +->| PLL1 | - reg 0x3036, for the multiplier 1147aa288248SMaxime Ripard * +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider 1148aa288248SMaxime Ripard * | +--------------+ 1149aa288248SMaxime Ripard * +->| System Clock | - reg 0x3035, bits 4-7 1150aa288248SMaxime Ripard * +-+------------+ 1151aa288248SMaxime Ripard * | +--------------+ 1152aa288248SMaxime Ripard * +->| MIPI Divider | - reg 0x3035, bits 0-3 1153aa288248SMaxime Ripard * | +-+------------+ 1154aa288248SMaxime Ripard * | +----------------> MIPI SCLK 1155aa288248SMaxime Ripard * | + +-----+ 1156aa288248SMaxime Ripard * | +->| / 2 |-------> MIPI BIT CLK 1157aa288248SMaxime Ripard * | +-----+ 1158aa288248SMaxime Ripard * | +--------------+ 1159aa288248SMaxime Ripard * +->| PLL Root Div | - reg 0x3037, bit 4 1160aa288248SMaxime Ripard * +-+------------+ 1161aa288248SMaxime Ripard * | +---------+ 11624c85f628SPaul Kocialkowski * +->| Bit Div | - reg 0x3034, bits 0-3 1163aa288248SMaxime Ripard * +-+-------+ 1164aa288248SMaxime Ripard * | +-------------+ 1165aa288248SMaxime Ripard * +->| SCLK Div | - reg 0x3108, bits 0-1 1166aa288248SMaxime Ripard * | +-+-----------+ 1167aa288248SMaxime Ripard * | +---------------> SCLK 1168aa288248SMaxime Ripard * | +-------------+ 1169aa288248SMaxime Ripard * +->| SCLK 2X Div | - reg 0x3108, bits 2-3 1170aa288248SMaxime Ripard * | +-+-----------+ 1171aa288248SMaxime Ripard * | +---------------> SCLK 2X 1172aa288248SMaxime Ripard * | +-------------+ 1173aa288248SMaxime Ripard * +->| PCLK Div | - reg 0x3108, bits 4-5 1174aa288248SMaxime Ripard * ++------------+ 1175aa288248SMaxime Ripard * + +-----------+ 1176aa288248SMaxime Ripard * +->| P_DIV | - reg 0x3035, bits 0-3 1177aa288248SMaxime Ripard * +-----+-----+ 1178aa288248SMaxime Ripard * +------------> PCLK 1179aa288248SMaxime Ripard * 11806c957ed7SJacopo Mondi * There seems to be also constraints: 1181aa288248SMaxime Ripard * - the PLL pre-divider output rate should be in the 4-27MHz range 1182aa288248SMaxime Ripard * - the PLL multiplier output rate should be in the 500-1000MHz range 1183aa288248SMaxime Ripard * - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG 1184aa288248SMaxime Ripard */ 1185aa288248SMaxime Ripard 1186aa288248SMaxime Ripard /* 1187aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1188aa288248SMaxime Ripard * set to 3 in the vendor kernels. 1189aa288248SMaxime Ripard */ 1190aa288248SMaxime Ripard #define OV5640_PLL_PREDIV 3 1191aa288248SMaxime Ripard 1192aa288248SMaxime Ripard #define OV5640_PLL_MULT_MIN 4 1193aa288248SMaxime Ripard #define OV5640_PLL_MULT_MAX 252 1194aa288248SMaxime Ripard 1195aa288248SMaxime Ripard /* 1196aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 16, but the value is 1197aa288248SMaxime Ripard * always set to either 1 or 2 in the vendor kernels. 1198aa288248SMaxime Ripard */ 1199aa288248SMaxime Ripard #define OV5640_SYSDIV_MIN 1 1200aa288248SMaxime Ripard #define OV5640_SYSDIV_MAX 16 1201aa288248SMaxime Ripard 1202aa288248SMaxime Ripard /* 1203aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 2, but the value is always 1204aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1205aa288248SMaxime Ripard */ 1206aa288248SMaxime Ripard #define OV5640_PLL_ROOT_DIV 2 1207aa288248SMaxime Ripard #define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4) 1208aa288248SMaxime Ripard 1209aa288248SMaxime Ripard /* 1210aa288248SMaxime Ripard * We only supports 8-bit formats at the moment 1211aa288248SMaxime Ripard */ 1212aa288248SMaxime Ripard #define OV5640_BIT_DIV 2 1213aa288248SMaxime Ripard #define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08 1214aa288248SMaxime Ripard 1215aa288248SMaxime Ripard /* 1216aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1217aa288248SMaxime Ripard * set to 2 in the vendor kernels. 1218aa288248SMaxime Ripard */ 1219aa288248SMaxime Ripard #define OV5640_SCLK_ROOT_DIV 2 1220aa288248SMaxime Ripard 1221aa288248SMaxime Ripard /* 1222aa288248SMaxime Ripard * This is hardcoded so that the consistency is maintained between SCLK and 1223aa288248SMaxime Ripard * SCLK 2x. 1224aa288248SMaxime Ripard */ 1225aa288248SMaxime Ripard #define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2) 1226aa288248SMaxime Ripard 1227aa288248SMaxime Ripard /* 1228aa288248SMaxime Ripard * This is supposed to be ranging from 1 to 8, but the value is always 1229aa288248SMaxime Ripard * set to 1 in the vendor kernels. 1230aa288248SMaxime Ripard */ 1231aa288248SMaxime Ripard #define OV5640_PCLK_ROOT_DIV 1 1232aa288248SMaxime Ripard #define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00 1233aa288248SMaxime Ripard 1234aa288248SMaxime Ripard static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor, 1235aa288248SMaxime Ripard u8 pll_prediv, u8 pll_mult, 1236aa288248SMaxime Ripard u8 sysdiv) 1237aa288248SMaxime Ripard { 1238aa288248SMaxime Ripard unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult; 1239aa288248SMaxime Ripard 1240aa288248SMaxime Ripard /* PLL1 output cannot exceed 1GHz. */ 1241aa288248SMaxime Ripard if (sysclk / 1000000 > 1000) 1242aa288248SMaxime Ripard return 0; 1243aa288248SMaxime Ripard 1244aa288248SMaxime Ripard return sysclk / sysdiv; 1245aa288248SMaxime Ripard } 1246aa288248SMaxime Ripard 1247aa288248SMaxime Ripard static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor, 1248aa288248SMaxime Ripard unsigned long rate, 1249aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, 1250aa288248SMaxime Ripard u8 *sysdiv) 1251aa288248SMaxime Ripard { 1252aa288248SMaxime Ripard unsigned long best = ~0; 1253aa288248SMaxime Ripard u8 best_sysdiv = 1, best_mult = 1; 1254aa288248SMaxime Ripard u8 _sysdiv, _pll_mult; 1255aa288248SMaxime Ripard 1256aa288248SMaxime Ripard for (_sysdiv = OV5640_SYSDIV_MIN; 1257aa288248SMaxime Ripard _sysdiv <= OV5640_SYSDIV_MAX; 1258aa288248SMaxime Ripard _sysdiv++) { 1259aa288248SMaxime Ripard for (_pll_mult = OV5640_PLL_MULT_MIN; 1260aa288248SMaxime Ripard _pll_mult <= OV5640_PLL_MULT_MAX; 1261aa288248SMaxime Ripard _pll_mult++) { 1262aa288248SMaxime Ripard unsigned long _rate; 1263aa288248SMaxime Ripard 1264aa288248SMaxime Ripard /* 1265aa288248SMaxime Ripard * The PLL multiplier cannot be odd if above 1266aa288248SMaxime Ripard * 127. 1267aa288248SMaxime Ripard */ 1268aa288248SMaxime Ripard if (_pll_mult > 127 && (_pll_mult % 2)) 1269aa288248SMaxime Ripard continue; 1270aa288248SMaxime Ripard 1271aa288248SMaxime Ripard _rate = ov5640_compute_sys_clk(sensor, 1272aa288248SMaxime Ripard OV5640_PLL_PREDIV, 1273aa288248SMaxime Ripard _pll_mult, _sysdiv); 1274aa288248SMaxime Ripard 1275aa288248SMaxime Ripard /* 1276aa288248SMaxime Ripard * We have reached the maximum allowed PLL1 output, 1277aa288248SMaxime Ripard * increase sysdiv. 1278aa288248SMaxime Ripard */ 12792e3df204SAdam Ford if (!_rate) 1280aa288248SMaxime Ripard break; 1281aa288248SMaxime Ripard 1282aa288248SMaxime Ripard /* 1283aa288248SMaxime Ripard * Prefer rates above the expected clock rate than 1284aa288248SMaxime Ripard * below, even if that means being less precise. 1285aa288248SMaxime Ripard */ 1286aa288248SMaxime Ripard if (_rate < rate) 1287aa288248SMaxime Ripard continue; 1288aa288248SMaxime Ripard 1289aa288248SMaxime Ripard if (abs(rate - _rate) < abs(rate - best)) { 1290aa288248SMaxime Ripard best = _rate; 1291aa288248SMaxime Ripard best_sysdiv = _sysdiv; 1292aa288248SMaxime Ripard best_mult = _pll_mult; 1293aa288248SMaxime Ripard } 1294aa288248SMaxime Ripard 1295aa288248SMaxime Ripard if (_rate == rate) 1296aa288248SMaxime Ripard goto out; 1297aa288248SMaxime Ripard } 1298aa288248SMaxime Ripard } 1299aa288248SMaxime Ripard 1300aa288248SMaxime Ripard out: 1301aa288248SMaxime Ripard *sysdiv = best_sysdiv; 1302aa288248SMaxime Ripard *pll_prediv = OV5640_PLL_PREDIV; 1303aa288248SMaxime Ripard *pll_mult = best_mult; 1304aa288248SMaxime Ripard 1305aa288248SMaxime Ripard return best; 1306aa288248SMaxime Ripard } 1307aa288248SMaxime Ripard 1308aa288248SMaxime Ripard /* 1309aa288248SMaxime Ripard * ov5640_set_mipi_pclk() - Calculate the clock tree configuration values 1310aa288248SMaxime Ripard * for the MIPI CSI-2 output. 1311aa288248SMaxime Ripard */ 13126c957ed7SJacopo Mondi static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor) 1313aa288248SMaxime Ripard { 13146c957ed7SJacopo Mondi u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div; 1315aa288248SMaxime Ripard u8 prediv, mult, sysdiv; 13166c957ed7SJacopo Mondi unsigned long link_freq; 13176c957ed7SJacopo Mondi unsigned long sysclk; 13186c957ed7SJacopo Mondi u8 pclk_period; 13196c957ed7SJacopo Mondi u32 sample_rate; 13206c957ed7SJacopo Mondi u32 num_lanes; 1321aa288248SMaxime Ripard int ret; 1322aa288248SMaxime Ripard 13236c957ed7SJacopo Mondi /* Use the link freq computed at ov5640_update_pixel_rate() time. */ 13246c957ed7SJacopo Mondi link_freq = sensor->current_link_freq; 13256c957ed7SJacopo Mondi 1326aa288248SMaxime Ripard /* 13276c957ed7SJacopo Mondi * - mipi_div - Additional divider for the MIPI lane clock. 13286c957ed7SJacopo Mondi * 13296c957ed7SJacopo Mondi * Higher link frequencies would make sysclk > 1GHz. 13306c957ed7SJacopo Mondi * Keep the sysclk low and do not divide in the MIPI domain. 1331aa288248SMaxime Ripard */ 13326c957ed7SJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) 13336c957ed7SJacopo Mondi mipi_div = 1; 1334aa288248SMaxime Ripard else 13356c957ed7SJacopo Mondi mipi_div = 2; 1336aa288248SMaxime Ripard 13376c957ed7SJacopo Mondi sysclk = link_freq * mipi_div; 13386c957ed7SJacopo Mondi ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv); 1339aa288248SMaxime Ripard 13406c957ed7SJacopo Mondi /* 13416c957ed7SJacopo Mondi * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio. 13426c957ed7SJacopo Mondi * 13436c957ed7SJacopo Mondi * - root_div = 2 (fixed) 13446c957ed7SJacopo Mondi * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5 13456c957ed7SJacopo Mondi * - pclk_div = 1 (fixed) 13466c957ed7SJacopo Mondi * - p_div = (2 lanes ? mipi_div : 2 * mipi_div) 13476c957ed7SJacopo Mondi * 13486c957ed7SJacopo Mondi * This results in the following MIPI_SCLK depending on the number 13496c957ed7SJacopo Mondi * of lanes: 13506c957ed7SJacopo Mondi * 13516c957ed7SJacopo Mondi * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK 13526c957ed7SJacopo Mondi * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK 13536c957ed7SJacopo Mondi */ 13546c957ed7SJacopo Mondi root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2; 13556c957ed7SJacopo Mondi bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT; 13566c957ed7SJacopo Mondi pclk_div = ilog2(OV5640_PCLK_ROOT_DIV); 1357aa288248SMaxime Ripard 13586c957ed7SJacopo Mondi /* 13596c957ed7SJacopo Mondi * Scaler clock: 13606c957ed7SJacopo Mondi * - YUV: PCLK >= 2 * SCLK 13616c957ed7SJacopo Mondi * - RAW or JPEG: PCLK >= SCLK 13626c957ed7SJacopo Mondi * - sclk2x_div = sclk_div / 2 13636c957ed7SJacopo Mondi */ 13646c957ed7SJacopo Mondi sclk_div = ilog2(OV5640_SCLK_ROOT_DIV); 13656c957ed7SJacopo Mondi sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV); 13666c957ed7SJacopo Mondi 13676c957ed7SJacopo Mondi /* 13686c957ed7SJacopo Mondi * Set the pixel clock period expressed in ns with 1-bit decimal 13696c957ed7SJacopo Mondi * (0x01=0.5ns). 13706c957ed7SJacopo Mondi * 13716c957ed7SJacopo Mondi * The register is very briefly documented. In the OV5645 datasheet it 13726c957ed7SJacopo Mondi * is described as (2 * pclk period), and from testing it seems the 13736c957ed7SJacopo Mondi * actual definition is 2 * 8-bit sample period. 13746c957ed7SJacopo Mondi * 13756c957ed7SJacopo Mondi * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2 13766c957ed7SJacopo Mondi */ 13776c957ed7SJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 13786c957ed7SJacopo Mondi sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16; 13796c957ed7SJacopo Mondi pclk_period = 2000000000UL / sample_rate; 13806c957ed7SJacopo Mondi 13816c957ed7SJacopo Mondi /* Program the clock tree registers. */ 13826c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div); 13836c957ed7SJacopo Mondi if (ret) 13846c957ed7SJacopo Mondi return ret; 13856c957ed7SJacopo Mondi 13866c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff, 13876c957ed7SJacopo Mondi (sysdiv << 4) | mipi_div); 1388aa288248SMaxime Ripard if (ret) 1389aa288248SMaxime Ripard return ret; 1390aa288248SMaxime Ripard 1391aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult); 1392aa288248SMaxime Ripard if (ret) 1393aa288248SMaxime Ripard return ret; 1394aa288248SMaxime Ripard 13956c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f, 13966c957ed7SJacopo Mondi root_div | prediv); 1397aa288248SMaxime Ripard if (ret) 1398aa288248SMaxime Ripard return ret; 1399aa288248SMaxime Ripard 14006c957ed7SJacopo Mondi ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 14016c957ed7SJacopo Mondi (pclk_div << 4) | (sclk2x_div << 2) | sclk_div); 14026c957ed7SJacopo Mondi if (ret) 14036c957ed7SJacopo Mondi return ret; 14046c957ed7SJacopo Mondi 14056c957ed7SJacopo Mondi return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period); 14066c957ed7SJacopo Mondi } 14076c957ed7SJacopo Mondi 14086c957ed7SJacopo Mondi static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) 14096c957ed7SJacopo Mondi { 14103145efcdSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 14115113d5b3SJacopo Mondi const struct ov5640_timings *timings = &mode->dvp_timings; 14126c957ed7SJacopo Mondi u32 rate; 14136c957ed7SJacopo Mondi 14145113d5b3SJacopo Mondi rate = timings->htot * (timings->crop.height + timings->vblank_def); 14156c957ed7SJacopo Mondi rate *= ov5640_framerates[sensor->current_fr]; 14166c957ed7SJacopo Mondi 14176c957ed7SJacopo Mondi return rate; 1418aa288248SMaxime Ripard } 1419aa288248SMaxime Ripard 1420aa288248SMaxime Ripard static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, 1421aa288248SMaxime Ripard unsigned long rate, 1422aa288248SMaxime Ripard u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv, 1423aa288248SMaxime Ripard u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div) 1424aa288248SMaxime Ripard { 1425aa288248SMaxime Ripard unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV * 1426aa288248SMaxime Ripard OV5640_PCLK_ROOT_DIV; 1427aa288248SMaxime Ripard 1428aa288248SMaxime Ripard _rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult, 1429aa288248SMaxime Ripard sysdiv); 1430aa288248SMaxime Ripard *pll_rdiv = OV5640_PLL_ROOT_DIV; 1431aa288248SMaxime Ripard *bit_div = OV5640_BIT_DIV; 1432aa288248SMaxime Ripard *pclk_div = OV5640_PCLK_ROOT_DIV; 1433aa288248SMaxime Ripard 1434aa288248SMaxime Ripard return _rate / *pll_rdiv / *bit_div / *pclk_div; 1435aa288248SMaxime Ripard } 1436aa288248SMaxime Ripard 14376c957ed7SJacopo Mondi static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor) 1438aa288248SMaxime Ripard { 1439aa288248SMaxime Ripard u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div; 14406c957ed7SJacopo Mondi u32 rate; 1441aa288248SMaxime Ripard int ret; 1442aa288248SMaxime Ripard 14436c957ed7SJacopo Mondi rate = ov5640_calc_pixel_rate(sensor); 14446c957ed7SJacopo Mondi rate *= ov5640_code_to_bpp(sensor->fmt.code); 14456c957ed7SJacopo Mondi rate /= sensor->ep.bus.parallel.bus_width; 14466c957ed7SJacopo Mondi 1447aa288248SMaxime Ripard ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv, 1448aa288248SMaxime Ripard &bit_div, &pclk_div); 1449aa288248SMaxime Ripard 1450aa288248SMaxime Ripard if (bit_div == 2) 1451aa288248SMaxime Ripard bit_div = 8; 1452aa288248SMaxime Ripard 1453aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 1454aa288248SMaxime Ripard 0x0f, bit_div); 1455aa288248SMaxime Ripard if (ret) 1456aa288248SMaxime Ripard return ret; 1457aa288248SMaxime Ripard 1458aa288248SMaxime Ripard /* 1459aa288248SMaxime Ripard * We need to set sysdiv according to the clock, and to clear 1460aa288248SMaxime Ripard * the MIPI divider. 1461aa288248SMaxime Ripard */ 1462aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 1463aa288248SMaxime Ripard 0xff, sysdiv << 4); 1464aa288248SMaxime Ripard if (ret) 1465aa288248SMaxime Ripard return ret; 1466aa288248SMaxime Ripard 1467aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 1468aa288248SMaxime Ripard 0xff, mult); 1469aa288248SMaxime Ripard if (ret) 1470aa288248SMaxime Ripard return ret; 1471aa288248SMaxime Ripard 1472aa288248SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 1473aa288248SMaxime Ripard 0x1f, prediv | ((pll_rdiv - 1) << 4)); 1474aa288248SMaxime Ripard if (ret) 1475aa288248SMaxime Ripard return ret; 1476aa288248SMaxime Ripard 1477aa288248SMaxime Ripard return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30, 1478aa288248SMaxime Ripard (ilog2(pclk_div) << 4)); 1479aa288248SMaxime Ripard } 1480aa288248SMaxime Ripard 14817cb013b1SChen-Yu Tsai /* set JPEG framing sizes */ 14827cb013b1SChen-Yu Tsai static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, 14837cb013b1SChen-Yu Tsai const struct ov5640_mode_info *mode) 14847cb013b1SChen-Yu Tsai { 14857cb013b1SChen-Yu Tsai int ret; 14867cb013b1SChen-Yu Tsai 14872b5c18f9SChen-Yu Tsai /* 14882b5c18f9SChen-Yu Tsai * compression mode 3 timing 14892b5c18f9SChen-Yu Tsai * 14902b5c18f9SChen-Yu Tsai * Data is transmitted with programmable width (VFIFO_HSIZE). 14912b5c18f9SChen-Yu Tsai * No padding done. Last line may have less data. Varying 14922b5c18f9SChen-Yu Tsai * number of lines per frame, depending on amount of data. 14932b5c18f9SChen-Yu Tsai */ 14942b5c18f9SChen-Yu Tsai ret = ov5640_mod_reg(sensor, OV5640_REG_JPG_MODE_SELECT, 0x7, 0x3); 14952b5c18f9SChen-Yu Tsai if (ret < 0) 14962b5c18f9SChen-Yu Tsai return ret; 14972b5c18f9SChen-Yu Tsai 14985113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width); 14997cb013b1SChen-Yu Tsai if (ret < 0) 15007cb013b1SChen-Yu Tsai return ret; 15017cb013b1SChen-Yu Tsai 15025113d5b3SJacopo Mondi return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height); 15037cb013b1SChen-Yu Tsai } 15047cb013b1SChen-Yu Tsai 150519a81c14SSteve Longerbeam /* download ov5640 settings to sensor through i2c */ 1506bad1774eSJacopo Mondi static int ov5640_set_timings(struct ov5640_dev *sensor, 1507bad1774eSJacopo Mondi const struct ov5640_mode_info *mode) 1508bad1774eSJacopo Mondi { 15095113d5b3SJacopo Mondi const struct ov5640_timings *timings; 15105113d5b3SJacopo Mondi const struct v4l2_rect *analog_crop; 15115113d5b3SJacopo Mondi const struct v4l2_rect *crop; 1512bad1774eSJacopo Mondi int ret; 1513bad1774eSJacopo Mondi 15147cb013b1SChen-Yu Tsai if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { 15157cb013b1SChen-Yu Tsai ret = ov5640_set_jpeg_timings(sensor, mode); 15167cb013b1SChen-Yu Tsai if (ret < 0) 15177cb013b1SChen-Yu Tsai return ret; 15187cb013b1SChen-Yu Tsai } 15197cb013b1SChen-Yu Tsai 15202de6bb97SJacopo Mondi timings = ov5640_timings(sensor, mode); 15215113d5b3SJacopo Mondi analog_crop = &timings->analog_crop; 15225113d5b3SJacopo Mondi crop = &timings->crop; 15235113d5b3SJacopo Mondi 15243145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS, 15253145efcdSJacopo Mondi analog_crop->left); 1526bad1774eSJacopo Mondi if (ret < 0) 1527bad1774eSJacopo Mondi return ret; 1528bad1774eSJacopo Mondi 15293145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS, 15303145efcdSJacopo Mondi analog_crop->top); 15313145efcdSJacopo Mondi if (ret < 0) 15323145efcdSJacopo Mondi return ret; 15333145efcdSJacopo Mondi 15343145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW, 15353145efcdSJacopo Mondi analog_crop->left + analog_crop->width - 1); 15363145efcdSJacopo Mondi if (ret < 0) 15373145efcdSJacopo Mondi return ret; 15383145efcdSJacopo Mondi 15393145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH, 15403145efcdSJacopo Mondi analog_crop->top + analog_crop->height - 1); 15413145efcdSJacopo Mondi if (ret < 0) 15423145efcdSJacopo Mondi return ret; 15433145efcdSJacopo Mondi 15443145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left); 15453145efcdSJacopo Mondi if (ret < 0) 15463145efcdSJacopo Mondi return ret; 15473145efcdSJacopo Mondi 15483145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top); 15493145efcdSJacopo Mondi if (ret < 0) 15503145efcdSJacopo Mondi return ret; 15513145efcdSJacopo Mondi 15525113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width); 15533145efcdSJacopo Mondi if (ret < 0) 15543145efcdSJacopo Mondi return ret; 15553145efcdSJacopo Mondi 15565113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height); 1557bad1774eSJacopo Mondi if (ret < 0) 1558bad1774eSJacopo Mondi return ret; 1559bad1774eSJacopo Mondi 15605113d5b3SJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot); 1561bad1774eSJacopo Mondi if (ret < 0) 1562bad1774eSJacopo Mondi return ret; 1563bad1774eSJacopo Mondi 15643145efcdSJacopo Mondi ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, 15655113d5b3SJacopo Mondi mode->height + timings->vblank_def); 15663145efcdSJacopo Mondi if (ret < 0) 15673145efcdSJacopo Mondi return ret; 15683145efcdSJacopo Mondi 15693145efcdSJacopo Mondi return 0; 1570bad1774eSJacopo Mondi } 1571bad1774eSJacopo Mondi 1572e4359019SJacopo Mondi static void ov5640_load_regs(struct ov5640_dev *sensor, 1573e4359019SJacopo Mondi const struct reg_value *regs, unsigned int regnum) 157419a81c14SSteve Longerbeam { 157519a81c14SSteve Longerbeam unsigned int i; 157619a81c14SSteve Longerbeam u32 delay_ms; 157719a81c14SSteve Longerbeam u16 reg_addr; 157819a81c14SSteve Longerbeam u8 mask, val; 157919a81c14SSteve Longerbeam int ret = 0; 158019a81c14SSteve Longerbeam 1581e4359019SJacopo Mondi for (i = 0; i < regnum; ++i, ++regs) { 158219a81c14SSteve Longerbeam delay_ms = regs->delay_ms; 158319a81c14SSteve Longerbeam reg_addr = regs->reg_addr; 158419a81c14SSteve Longerbeam val = regs->val; 158519a81c14SSteve Longerbeam mask = regs->mask; 158619a81c14SSteve Longerbeam 15873b987d70SLad Prabhakar /* remain in power down mode for DVP */ 15883b987d70SLad Prabhakar if (regs->reg_addr == OV5640_REG_SYS_CTRL0 && 15893b987d70SLad Prabhakar val == OV5640_REG_SYS_CTRL0_SW_PWUP && 15908e823f5cSJacopo Mondi !ov5640_is_csi2(sensor)) 15913b987d70SLad Prabhakar continue; 15923b987d70SLad Prabhakar 159319a81c14SSteve Longerbeam if (mask) 159419a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, reg_addr, mask, val); 159519a81c14SSteve Longerbeam else 159619a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, reg_addr, val); 159719a81c14SSteve Longerbeam if (ret) 159819a81c14SSteve Longerbeam break; 159919a81c14SSteve Longerbeam 160019a81c14SSteve Longerbeam if (delay_ms) 160119a81c14SSteve Longerbeam usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); 160219a81c14SSteve Longerbeam } 160319a81c14SSteve Longerbeam } 160419a81c14SSteve Longerbeam 1605dc29a1c1SHugues Fruchet static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on) 1606dc29a1c1SHugues Fruchet { 1607dc29a1c1SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 1608dc29a1c1SHugues Fruchet BIT(0), on ? 0 : BIT(0)); 1609dc29a1c1SHugues Fruchet } 1610dc29a1c1SHugues Fruchet 161119a81c14SSteve Longerbeam /* read exposure, in number of line periods */ 161219a81c14SSteve Longerbeam static int ov5640_get_exposure(struct ov5640_dev *sensor) 161319a81c14SSteve Longerbeam { 161419a81c14SSteve Longerbeam int exp, ret; 161519a81c14SSteve Longerbeam u8 temp; 161619a81c14SSteve Longerbeam 161719a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_HI, &temp); 161819a81c14SSteve Longerbeam if (ret) 161919a81c14SSteve Longerbeam return ret; 162019a81c14SSteve Longerbeam exp = ((int)temp & 0x0f) << 16; 162119a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_MED, &temp); 162219a81c14SSteve Longerbeam if (ret) 162319a81c14SSteve Longerbeam return ret; 162419a81c14SSteve Longerbeam exp |= ((int)temp << 8); 162519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_PK_EXPOSURE_LO, &temp); 162619a81c14SSteve Longerbeam if (ret) 162719a81c14SSteve Longerbeam return ret; 162819a81c14SSteve Longerbeam exp |= (int)temp; 162919a81c14SSteve Longerbeam 163019a81c14SSteve Longerbeam return exp >> 4; 163119a81c14SSteve Longerbeam } 163219a81c14SSteve Longerbeam 163319a81c14SSteve Longerbeam /* write exposure, given number of line periods */ 163419a81c14SSteve Longerbeam static int ov5640_set_exposure(struct ov5640_dev *sensor, u32 exposure) 163519a81c14SSteve Longerbeam { 163619a81c14SSteve Longerbeam int ret; 163719a81c14SSteve Longerbeam 163819a81c14SSteve Longerbeam exposure <<= 4; 163919a81c14SSteve Longerbeam 164019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 164119a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_LO, 164219a81c14SSteve Longerbeam exposure & 0xff); 164319a81c14SSteve Longerbeam if (ret) 164419a81c14SSteve Longerbeam return ret; 164519a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, 164619a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_MED, 164719a81c14SSteve Longerbeam (exposure >> 8) & 0xff); 164819a81c14SSteve Longerbeam if (ret) 164919a81c14SSteve Longerbeam return ret; 165019a81c14SSteve Longerbeam return ov5640_write_reg(sensor, 165119a81c14SSteve Longerbeam OV5640_REG_AEC_PK_EXPOSURE_HI, 165219a81c14SSteve Longerbeam (exposure >> 16) & 0x0f); 165319a81c14SSteve Longerbeam } 165419a81c14SSteve Longerbeam 165519a81c14SSteve Longerbeam static int ov5640_get_gain(struct ov5640_dev *sensor) 165619a81c14SSteve Longerbeam { 165719a81c14SSteve Longerbeam u16 gain; 165819a81c14SSteve Longerbeam int ret; 165919a81c14SSteve Longerbeam 166019a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, &gain); 166119a81c14SSteve Longerbeam if (ret) 166219a81c14SSteve Longerbeam return ret; 166319a81c14SSteve Longerbeam 166419a81c14SSteve Longerbeam return gain & 0x3ff; 166519a81c14SSteve Longerbeam } 166619a81c14SSteve Longerbeam 16673cca8ef5SHugues Fruchet static int ov5640_set_gain(struct ov5640_dev *sensor, int gain) 16683cca8ef5SHugues Fruchet { 16693cca8ef5SHugues Fruchet return ov5640_write_reg16(sensor, OV5640_REG_AEC_PK_REAL_GAIN, 16703cca8ef5SHugues Fruchet (u16)gain & 0x3ff); 16713cca8ef5SHugues Fruchet } 16723cca8ef5SHugues Fruchet 16733cca8ef5SHugues Fruchet static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on) 16743cca8ef5SHugues Fruchet { 16753cca8ef5SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_AEC_PK_MANUAL, 16763cca8ef5SHugues Fruchet BIT(1), on ? 0 : BIT(1)); 16773cca8ef5SHugues Fruchet } 16783cca8ef5SHugues Fruchet 1679f22996dbSHugues Fruchet static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) 1680f22996dbSHugues Fruchet { 16813b987d70SLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ? 16823b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWUP : 16833b987d70SLad Prabhakar OV5640_REG_SYS_CTRL0_SW_PWDN); 1684f22996dbSHugues Fruchet } 1685f22996dbSHugues Fruchet 1686f22996dbSHugues Fruchet static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) 168719a81c14SSteve Longerbeam { 168819a81c14SSteve Longerbeam int ret; 168919a81c14SSteve Longerbeam 1690aa4bb8b8SJacopo Mondi /* 1691aa4bb8b8SJacopo Mondi * Enable/disable the MIPI interface 1692aa4bb8b8SJacopo Mondi * 1693aa4bb8b8SJacopo Mondi * 0x300e = on ? 0x45 : 0x40 1694aa4bb8b8SJacopo Mondi * 1695aa4bb8b8SJacopo Mondi * FIXME: the sensor manual (version 2.03) reports 1696aa4bb8b8SJacopo Mondi * [7:5] = 000 : 1 data lane mode 1697aa4bb8b8SJacopo Mondi * [7:5] = 001 : 2 data lanes mode 1698aa4bb8b8SJacopo Mondi * But this settings do not work, while the following ones 1699aa4bb8b8SJacopo Mondi * have been validated for 2 data lanes mode. 1700aa4bb8b8SJacopo Mondi * 1701aa4bb8b8SJacopo Mondi * [7:5] = 010 : 2 data lanes mode 1702aa4bb8b8SJacopo Mondi * [4] = 0 : Power up MIPI HS Tx 1703aa4bb8b8SJacopo Mondi * [3] = 0 : Power up MIPI LS Rx 1704aa4bb8b8SJacopo Mondi * [2] = 1/0 : MIPI interface enable/disable 1705aa4bb8b8SJacopo Mondi * [1:0] = 01/00: FIXME: 'debug' 1706aa4bb8b8SJacopo Mondi */ 1707aa4bb8b8SJacopo Mondi ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 1708aa4bb8b8SJacopo Mondi on ? 0x45 : 0x40); 170919a81c14SSteve Longerbeam if (ret) 171019a81c14SSteve Longerbeam return ret; 171119a81c14SSteve Longerbeam 171219a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_FRAME_CTRL01, 171319a81c14SSteve Longerbeam on ? 0x00 : 0x0f); 171419a81c14SSteve Longerbeam } 171519a81c14SSteve Longerbeam 171619a81c14SSteve Longerbeam static int ov5640_get_sysclk(struct ov5640_dev *sensor) 171719a81c14SSteve Longerbeam { 171819a81c14SSteve Longerbeam /* calculate sysclk */ 171919a81c14SSteve Longerbeam u32 xvclk = sensor->xclk_freq / 10000; 172019a81c14SSteve Longerbeam u32 multiplier, prediv, VCO, sysdiv, pll_rdiv; 172119a81c14SSteve Longerbeam u32 sclk_rdiv_map[] = {1, 2, 4, 8}; 172219a81c14SSteve Longerbeam u32 bit_div2x = 1, sclk_rdiv, sysclk; 172319a81c14SSteve Longerbeam u8 temp1, temp2; 172419a81c14SSteve Longerbeam int ret; 172519a81c14SSteve Longerbeam 172619a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL0, &temp1); 172719a81c14SSteve Longerbeam if (ret) 172819a81c14SSteve Longerbeam return ret; 172919a81c14SSteve Longerbeam temp2 = temp1 & 0x0f; 173019a81c14SSteve Longerbeam if (temp2 == 8 || temp2 == 10) 173119a81c14SSteve Longerbeam bit_div2x = temp2 / 2; 173219a81c14SSteve Longerbeam 173319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL1, &temp1); 173419a81c14SSteve Longerbeam if (ret) 173519a81c14SSteve Longerbeam return ret; 173619a81c14SSteve Longerbeam sysdiv = temp1 >> 4; 173719a81c14SSteve Longerbeam if (sysdiv == 0) 173819a81c14SSteve Longerbeam sysdiv = 16; 173919a81c14SSteve Longerbeam 174019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL2, &temp1); 174119a81c14SSteve Longerbeam if (ret) 174219a81c14SSteve Longerbeam return ret; 174319a81c14SSteve Longerbeam multiplier = temp1; 174419a81c14SSteve Longerbeam 174519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SC_PLL_CTRL3, &temp1); 174619a81c14SSteve Longerbeam if (ret) 174719a81c14SSteve Longerbeam return ret; 174819a81c14SSteve Longerbeam prediv = temp1 & 0x0f; 174919a81c14SSteve Longerbeam pll_rdiv = ((temp1 >> 4) & 0x01) + 1; 175019a81c14SSteve Longerbeam 175119a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, &temp1); 175219a81c14SSteve Longerbeam if (ret) 175319a81c14SSteve Longerbeam return ret; 175419a81c14SSteve Longerbeam temp2 = temp1 & 0x03; 175519a81c14SSteve Longerbeam sclk_rdiv = sclk_rdiv_map[temp2]; 175619a81c14SSteve Longerbeam 175719a81c14SSteve Longerbeam if (!prediv || !sysdiv || !pll_rdiv || !bit_div2x) 175819a81c14SSteve Longerbeam return -EINVAL; 175919a81c14SSteve Longerbeam 176019a81c14SSteve Longerbeam VCO = xvclk * multiplier / prediv; 176119a81c14SSteve Longerbeam 176219a81c14SSteve Longerbeam sysclk = VCO / sysdiv / pll_rdiv * 2 / bit_div2x / sclk_rdiv; 176319a81c14SSteve Longerbeam 176419a81c14SSteve Longerbeam return sysclk; 176519a81c14SSteve Longerbeam } 176619a81c14SSteve Longerbeam 176719a81c14SSteve Longerbeam static int ov5640_set_night_mode(struct ov5640_dev *sensor) 176819a81c14SSteve Longerbeam { 176919a81c14SSteve Longerbeam /* read HTS from register settings */ 177019a81c14SSteve Longerbeam u8 mode; 177119a81c14SSteve Longerbeam int ret; 177219a81c14SSteve Longerbeam 177319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AEC_CTRL00, &mode); 177419a81c14SSteve Longerbeam if (ret) 177519a81c14SSteve Longerbeam return ret; 177619a81c14SSteve Longerbeam mode &= 0xfb; 177719a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL00, mode); 177819a81c14SSteve Longerbeam } 177919a81c14SSteve Longerbeam 178019a81c14SSteve Longerbeam static int ov5640_get_hts(struct ov5640_dev *sensor) 178119a81c14SSteve Longerbeam { 178219a81c14SSteve Longerbeam /* read HTS from register settings */ 178319a81c14SSteve Longerbeam u16 hts; 178419a81c14SSteve Longerbeam int ret; 178519a81c14SSteve Longerbeam 178619a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_HTS, &hts); 178719a81c14SSteve Longerbeam if (ret) 178819a81c14SSteve Longerbeam return ret; 178919a81c14SSteve Longerbeam return hts; 179019a81c14SSteve Longerbeam } 179119a81c14SSteve Longerbeam 179219a81c14SSteve Longerbeam static int ov5640_get_vts(struct ov5640_dev *sensor) 179319a81c14SSteve Longerbeam { 179419a81c14SSteve Longerbeam u16 vts; 179519a81c14SSteve Longerbeam int ret; 179619a81c14SSteve Longerbeam 179719a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_TIMING_VTS, &vts); 179819a81c14SSteve Longerbeam if (ret) 179919a81c14SSteve Longerbeam return ret; 180019a81c14SSteve Longerbeam return vts; 180119a81c14SSteve Longerbeam } 180219a81c14SSteve Longerbeam 180319a81c14SSteve Longerbeam static int ov5640_set_vts(struct ov5640_dev *sensor, int vts) 180419a81c14SSteve Longerbeam { 180519a81c14SSteve Longerbeam return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, vts); 180619a81c14SSteve Longerbeam } 180719a81c14SSteve Longerbeam 180819a81c14SSteve Longerbeam static int ov5640_get_light_freq(struct ov5640_dev *sensor) 180919a81c14SSteve Longerbeam { 181019a81c14SSteve Longerbeam /* get banding filter value */ 181119a81c14SSteve Longerbeam int ret, light_freq = 0; 181219a81c14SSteve Longerbeam u8 temp, temp1; 181319a81c14SSteve Longerbeam 181419a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL01, &temp); 181519a81c14SSteve Longerbeam if (ret) 181619a81c14SSteve Longerbeam return ret; 181719a81c14SSteve Longerbeam 181819a81c14SSteve Longerbeam if (temp & 0x80) { 181919a81c14SSteve Longerbeam /* manual */ 182019a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_HZ5060_CTRL00, 182119a81c14SSteve Longerbeam &temp1); 182219a81c14SSteve Longerbeam if (ret) 182319a81c14SSteve Longerbeam return ret; 182419a81c14SSteve Longerbeam if (temp1 & 0x04) { 182519a81c14SSteve Longerbeam /* 50Hz */ 182619a81c14SSteve Longerbeam light_freq = 50; 182719a81c14SSteve Longerbeam } else { 182819a81c14SSteve Longerbeam /* 60Hz */ 182919a81c14SSteve Longerbeam light_freq = 60; 183019a81c14SSteve Longerbeam } 183119a81c14SSteve Longerbeam } else { 183219a81c14SSteve Longerbeam /* auto */ 183319a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_SIGMADELTA_CTRL0C, 183419a81c14SSteve Longerbeam &temp1); 183519a81c14SSteve Longerbeam if (ret) 183619a81c14SSteve Longerbeam return ret; 183719a81c14SSteve Longerbeam 183819a81c14SSteve Longerbeam if (temp1 & 0x01) { 183919a81c14SSteve Longerbeam /* 50Hz */ 184019a81c14SSteve Longerbeam light_freq = 50; 184119a81c14SSteve Longerbeam } else { 184219a81c14SSteve Longerbeam /* 60Hz */ 184319a81c14SSteve Longerbeam } 184419a81c14SSteve Longerbeam } 184519a81c14SSteve Longerbeam 184619a81c14SSteve Longerbeam return light_freq; 184719a81c14SSteve Longerbeam } 184819a81c14SSteve Longerbeam 184919a81c14SSteve Longerbeam static int ov5640_set_bandingfilter(struct ov5640_dev *sensor) 185019a81c14SSteve Longerbeam { 185119a81c14SSteve Longerbeam u32 band_step60, max_band60, band_step50, max_band50, prev_vts; 185219a81c14SSteve Longerbeam int ret; 185319a81c14SSteve Longerbeam 185419a81c14SSteve Longerbeam /* read preview PCLK */ 185519a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 185619a81c14SSteve Longerbeam if (ret < 0) 185719a81c14SSteve Longerbeam return ret; 185819a81c14SSteve Longerbeam if (ret == 0) 185919a81c14SSteve Longerbeam return -EINVAL; 186019a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 186119a81c14SSteve Longerbeam /* read preview HTS */ 186219a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 186319a81c14SSteve Longerbeam if (ret < 0) 186419a81c14SSteve Longerbeam return ret; 186519a81c14SSteve Longerbeam if (ret == 0) 186619a81c14SSteve Longerbeam return -EINVAL; 186719a81c14SSteve Longerbeam sensor->prev_hts = ret; 186819a81c14SSteve Longerbeam 186919a81c14SSteve Longerbeam /* read preview VTS */ 187019a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 187119a81c14SSteve Longerbeam if (ret < 0) 187219a81c14SSteve Longerbeam return ret; 187319a81c14SSteve Longerbeam prev_vts = ret; 187419a81c14SSteve Longerbeam 187519a81c14SSteve Longerbeam /* calculate banding filter */ 187619a81c14SSteve Longerbeam /* 60Hz */ 187719a81c14SSteve Longerbeam band_step60 = sensor->prev_sysclk * 100 / sensor->prev_hts * 100 / 120; 187819a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B60_STEP, band_step60); 187919a81c14SSteve Longerbeam if (ret) 188019a81c14SSteve Longerbeam return ret; 188119a81c14SSteve Longerbeam if (!band_step60) 188219a81c14SSteve Longerbeam return -EINVAL; 188319a81c14SSteve Longerbeam max_band60 = (int)((prev_vts - 4) / band_step60); 188419a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0D, max_band60); 188519a81c14SSteve Longerbeam if (ret) 188619a81c14SSteve Longerbeam return ret; 188719a81c14SSteve Longerbeam 188819a81c14SSteve Longerbeam /* 50Hz */ 188919a81c14SSteve Longerbeam band_step50 = sensor->prev_sysclk * 100 / sensor->prev_hts; 189019a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AEC_B50_STEP, band_step50); 189119a81c14SSteve Longerbeam if (ret) 189219a81c14SSteve Longerbeam return ret; 189319a81c14SSteve Longerbeam if (!band_step50) 189419a81c14SSteve Longerbeam return -EINVAL; 189519a81c14SSteve Longerbeam max_band50 = (int)((prev_vts - 4) / band_step50); 189619a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0E, max_band50); 189719a81c14SSteve Longerbeam } 189819a81c14SSteve Longerbeam 189919a81c14SSteve Longerbeam static int ov5640_set_ae_target(struct ov5640_dev *sensor, int target) 190019a81c14SSteve Longerbeam { 190119a81c14SSteve Longerbeam /* stable in high */ 190219a81c14SSteve Longerbeam u32 fast_high, fast_low; 190319a81c14SSteve Longerbeam int ret; 190419a81c14SSteve Longerbeam 190519a81c14SSteve Longerbeam sensor->ae_low = target * 23 / 25; /* 0.92 */ 190619a81c14SSteve Longerbeam sensor->ae_high = target * 27 / 25; /* 1.08 */ 190719a81c14SSteve Longerbeam 190819a81c14SSteve Longerbeam fast_high = sensor->ae_high << 1; 190919a81c14SSteve Longerbeam if (fast_high > 255) 191019a81c14SSteve Longerbeam fast_high = 255; 191119a81c14SSteve Longerbeam 191219a81c14SSteve Longerbeam fast_low = sensor->ae_low >> 1; 191319a81c14SSteve Longerbeam 191419a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL0F, sensor->ae_high); 191519a81c14SSteve Longerbeam if (ret) 191619a81c14SSteve Longerbeam return ret; 191719a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL10, sensor->ae_low); 191819a81c14SSteve Longerbeam if (ret) 191919a81c14SSteve Longerbeam return ret; 192019a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1B, sensor->ae_high); 192119a81c14SSteve Longerbeam if (ret) 192219a81c14SSteve Longerbeam return ret; 192319a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1E, sensor->ae_low); 192419a81c14SSteve Longerbeam if (ret) 192519a81c14SSteve Longerbeam return ret; 192619a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL11, fast_high); 192719a81c14SSteve Longerbeam if (ret) 192819a81c14SSteve Longerbeam return ret; 192919a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_AEC_CTRL1F, fast_low); 193019a81c14SSteve Longerbeam } 193119a81c14SSteve Longerbeam 1932c2c3f42dSHugues Fruchet static int ov5640_get_binning(struct ov5640_dev *sensor) 193319a81c14SSteve Longerbeam { 193419a81c14SSteve Longerbeam u8 temp; 193519a81c14SSteve Longerbeam int ret; 193619a81c14SSteve Longerbeam 193719a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_TIMING_TC_REG21, &temp); 193819a81c14SSteve Longerbeam if (ret) 193919a81c14SSteve Longerbeam return ret; 1940c2c3f42dSHugues Fruchet 1941c2c3f42dSHugues Fruchet return temp & BIT(0); 194219a81c14SSteve Longerbeam } 194319a81c14SSteve Longerbeam 1944ce85705aSHugues Fruchet static int ov5640_set_binning(struct ov5640_dev *sensor, bool enable) 1945ce85705aSHugues Fruchet { 1946ce85705aSHugues Fruchet int ret; 1947ce85705aSHugues Fruchet 1948ce85705aSHugues Fruchet /* 1949ce85705aSHugues Fruchet * TIMING TC REG21: 1950ce85705aSHugues Fruchet * - [0]: Horizontal binning enable 1951ce85705aSHugues Fruchet */ 1952ce85705aSHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 1953ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 1954ce85705aSHugues Fruchet if (ret) 1955ce85705aSHugues Fruchet return ret; 1956ce85705aSHugues Fruchet /* 1957ce85705aSHugues Fruchet * TIMING TC REG20: 1958ce85705aSHugues Fruchet * - [0]: Undocumented, but hardcoded init sequences 1959ce85705aSHugues Fruchet * are always setting REG21/REG20 bit 0 to same value... 1960ce85705aSHugues Fruchet */ 1961ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 1962ce85705aSHugues Fruchet BIT(0), enable ? BIT(0) : 0); 1963ce85705aSHugues Fruchet } 1964ce85705aSHugues Fruchet 196519a81c14SSteve Longerbeam static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) 196619a81c14SSteve Longerbeam { 19678670d70aSHugues Fruchet struct i2c_client *client = sensor->i2c_client; 196819a81c14SSteve Longerbeam u8 temp, channel = virtual_channel; 196919a81c14SSteve Longerbeam int ret; 197019a81c14SSteve Longerbeam 19718670d70aSHugues Fruchet if (channel > 3) { 19728670d70aSHugues Fruchet dev_err(&client->dev, 19738670d70aSHugues Fruchet "%s: wrong virtual_channel parameter, expected (0..3), got %d\n", 19748670d70aSHugues Fruchet __func__, channel); 197519a81c14SSteve Longerbeam return -EINVAL; 19768670d70aSHugues Fruchet } 197719a81c14SSteve Longerbeam 197819a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_DEBUG_MODE, &temp); 197919a81c14SSteve Longerbeam if (ret) 198019a81c14SSteve Longerbeam return ret; 198119a81c14SSteve Longerbeam temp &= ~(3 << 6); 198219a81c14SSteve Longerbeam temp |= (channel << 6); 198319a81c14SSteve Longerbeam return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); 198419a81c14SSteve Longerbeam } 198519a81c14SSteve Longerbeam 198619a81c14SSteve Longerbeam static const struct ov5640_mode_info * 198719a81c14SSteve Longerbeam ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, 198819a81c14SSteve Longerbeam int width, int height, bool nearest) 198919a81c14SSteve Longerbeam { 19903c4a7372SHugues Fruchet const struct ov5640_mode_info *mode; 199119a81c14SSteve Longerbeam 1992086c25f8SMaxime Ripard mode = v4l2_find_nearest_size(ov5640_mode_data, 1993086c25f8SMaxime Ripard ARRAY_SIZE(ov5640_mode_data), 19945113d5b3SJacopo Mondi width, height, width, height); 199519a81c14SSteve Longerbeam 19963c4a7372SHugues Fruchet if (!mode || 19973145efcdSJacopo Mondi (!nearest && 19985113d5b3SJacopo Mondi (mode->width != width || mode->height != height))) 19993c4a7372SHugues Fruchet return NULL; 200019a81c14SSteve Longerbeam 20015554c80eSAdam Ford /* Check to see if the current mode exceeds the max frame rate */ 20025554c80eSAdam Ford if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps]) 2003981e4454SBenoit Parrot return NULL; 2004981e4454SBenoit Parrot 200519a81c14SSteve Longerbeam return mode; 200619a81c14SSteve Longerbeam } 200719a81c14SSteve Longerbeam 200819a81c14SSteve Longerbeam /* 200919a81c14SSteve Longerbeam * sensor changes between scaling and subsampling, go through 201019a81c14SSteve Longerbeam * exposure calculation 201119a81c14SSteve Longerbeam */ 201241d8d7f5SHugues Fruchet static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor, 201341d8d7f5SHugues Fruchet const struct ov5640_mode_info *mode) 201419a81c14SSteve Longerbeam { 201519a81c14SSteve Longerbeam u32 prev_shutter, prev_gain16; 201619a81c14SSteve Longerbeam u32 cap_shutter, cap_gain16; 201719a81c14SSteve Longerbeam u32 cap_sysclk, cap_hts, cap_vts; 201819a81c14SSteve Longerbeam u32 light_freq, cap_bandfilt, cap_maxband; 201919a81c14SSteve Longerbeam u32 cap_gain16_shutter; 202019a81c14SSteve Longerbeam u8 average; 202119a81c14SSteve Longerbeam int ret; 202219a81c14SSteve Longerbeam 202341d8d7f5SHugues Fruchet if (!mode->reg_data) 202419a81c14SSteve Longerbeam return -EINVAL; 202519a81c14SSteve Longerbeam 202619a81c14SSteve Longerbeam /* read preview shutter */ 202719a81c14SSteve Longerbeam ret = ov5640_get_exposure(sensor); 202819a81c14SSteve Longerbeam if (ret < 0) 202919a81c14SSteve Longerbeam return ret; 203019a81c14SSteve Longerbeam prev_shutter = ret; 2031c2c3f42dSHugues Fruchet ret = ov5640_get_binning(sensor); 203219a81c14SSteve Longerbeam if (ret < 0) 203319a81c14SSteve Longerbeam return ret; 203419a81c14SSteve Longerbeam if (ret && mode->id != OV5640_MODE_720P_1280_720 && 203519a81c14SSteve Longerbeam mode->id != OV5640_MODE_1080P_1920_1080) 203619a81c14SSteve Longerbeam prev_shutter *= 2; 203719a81c14SSteve Longerbeam 203819a81c14SSteve Longerbeam /* read preview gain */ 203919a81c14SSteve Longerbeam ret = ov5640_get_gain(sensor); 204019a81c14SSteve Longerbeam if (ret < 0) 204119a81c14SSteve Longerbeam return ret; 204219a81c14SSteve Longerbeam prev_gain16 = ret; 204319a81c14SSteve Longerbeam 204419a81c14SSteve Longerbeam /* get average */ 204519a81c14SSteve Longerbeam ret = ov5640_read_reg(sensor, OV5640_REG_AVG_READOUT, &average); 204619a81c14SSteve Longerbeam if (ret) 204719a81c14SSteve Longerbeam return ret; 204819a81c14SSteve Longerbeam 204919a81c14SSteve Longerbeam /* turn off night mode for capture */ 205019a81c14SSteve Longerbeam ret = ov5640_set_night_mode(sensor); 205119a81c14SSteve Longerbeam if (ret < 0) 205219a81c14SSteve Longerbeam return ret; 205319a81c14SSteve Longerbeam 205419a81c14SSteve Longerbeam /* Write capture setting */ 2055e4359019SJacopo Mondi ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); 2056e4359019SJacopo Mondi ret = ov5640_set_timings(sensor, mode); 205719a81c14SSteve Longerbeam if (ret < 0) 205819a81c14SSteve Longerbeam return ret; 205919a81c14SSteve Longerbeam 206019a81c14SSteve Longerbeam /* read capture VTS */ 206119a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 206219a81c14SSteve Longerbeam if (ret < 0) 206319a81c14SSteve Longerbeam return ret; 206419a81c14SSteve Longerbeam cap_vts = ret; 206519a81c14SSteve Longerbeam ret = ov5640_get_hts(sensor); 206619a81c14SSteve Longerbeam if (ret < 0) 206719a81c14SSteve Longerbeam return ret; 206819a81c14SSteve Longerbeam if (ret == 0) 206919a81c14SSteve Longerbeam return -EINVAL; 207019a81c14SSteve Longerbeam cap_hts = ret; 207119a81c14SSteve Longerbeam 207219a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 207319a81c14SSteve Longerbeam if (ret < 0) 207419a81c14SSteve Longerbeam return ret; 207519a81c14SSteve Longerbeam if (ret == 0) 207619a81c14SSteve Longerbeam return -EINVAL; 207719a81c14SSteve Longerbeam cap_sysclk = ret; 207819a81c14SSteve Longerbeam 207919a81c14SSteve Longerbeam /* calculate capture banding filter */ 208019a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 208119a81c14SSteve Longerbeam if (ret < 0) 208219a81c14SSteve Longerbeam return ret; 208319a81c14SSteve Longerbeam light_freq = ret; 208419a81c14SSteve Longerbeam 208519a81c14SSteve Longerbeam if (light_freq == 60) { 208619a81c14SSteve Longerbeam /* 60Hz */ 208719a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts * 100 / 120; 208819a81c14SSteve Longerbeam } else { 208919a81c14SSteve Longerbeam /* 50Hz */ 209019a81c14SSteve Longerbeam cap_bandfilt = cap_sysclk * 100 / cap_hts; 209119a81c14SSteve Longerbeam } 209219a81c14SSteve Longerbeam 209319a81c14SSteve Longerbeam if (!sensor->prev_sysclk) { 209419a81c14SSteve Longerbeam ret = ov5640_get_sysclk(sensor); 209519a81c14SSteve Longerbeam if (ret < 0) 209619a81c14SSteve Longerbeam return ret; 209719a81c14SSteve Longerbeam if (ret == 0) 209819a81c14SSteve Longerbeam return -EINVAL; 209919a81c14SSteve Longerbeam sensor->prev_sysclk = ret; 210019a81c14SSteve Longerbeam } 210119a81c14SSteve Longerbeam 210219a81c14SSteve Longerbeam if (!cap_bandfilt) 210319a81c14SSteve Longerbeam return -EINVAL; 210419a81c14SSteve Longerbeam 210519a81c14SSteve Longerbeam cap_maxband = (int)((cap_vts - 4) / cap_bandfilt); 210619a81c14SSteve Longerbeam 210719a81c14SSteve Longerbeam /* calculate capture shutter/gain16 */ 210819a81c14SSteve Longerbeam if (average > sensor->ae_low && average < sensor->ae_high) { 210919a81c14SSteve Longerbeam /* in stable range */ 211019a81c14SSteve Longerbeam cap_gain16_shutter = 211119a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 211219a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 211319a81c14SSteve Longerbeam sensor->prev_hts / cap_hts * 211419a81c14SSteve Longerbeam sensor->ae_target / average; 211519a81c14SSteve Longerbeam } else { 211619a81c14SSteve Longerbeam cap_gain16_shutter = 211719a81c14SSteve Longerbeam prev_gain16 * prev_shutter * 211819a81c14SSteve Longerbeam cap_sysclk / sensor->prev_sysclk * 211919a81c14SSteve Longerbeam sensor->prev_hts / cap_hts; 212019a81c14SSteve Longerbeam } 212119a81c14SSteve Longerbeam 212219a81c14SSteve Longerbeam /* gain to shutter */ 212319a81c14SSteve Longerbeam if (cap_gain16_shutter < (cap_bandfilt * 16)) { 212419a81c14SSteve Longerbeam /* shutter < 1/100 */ 212519a81c14SSteve Longerbeam cap_shutter = cap_gain16_shutter / 16; 212619a81c14SSteve Longerbeam if (cap_shutter < 1) 212719a81c14SSteve Longerbeam cap_shutter = 1; 212819a81c14SSteve Longerbeam 212919a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 213019a81c14SSteve Longerbeam if (cap_gain16 < 16) 213119a81c14SSteve Longerbeam cap_gain16 = 16; 213219a81c14SSteve Longerbeam } else { 213319a81c14SSteve Longerbeam if (cap_gain16_shutter > (cap_bandfilt * cap_maxband * 16)) { 213419a81c14SSteve Longerbeam /* exposure reach max */ 213519a81c14SSteve Longerbeam cap_shutter = cap_bandfilt * cap_maxband; 213619a81c14SSteve Longerbeam if (!cap_shutter) 213719a81c14SSteve Longerbeam return -EINVAL; 213819a81c14SSteve Longerbeam 213919a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 214019a81c14SSteve Longerbeam } else { 214119a81c14SSteve Longerbeam /* 1/100 < (cap_shutter = n/100) =< max */ 214219a81c14SSteve Longerbeam cap_shutter = 214319a81c14SSteve Longerbeam ((int)(cap_gain16_shutter / 16 / cap_bandfilt)) 214419a81c14SSteve Longerbeam * cap_bandfilt; 214519a81c14SSteve Longerbeam if (!cap_shutter) 214619a81c14SSteve Longerbeam return -EINVAL; 214719a81c14SSteve Longerbeam 214819a81c14SSteve Longerbeam cap_gain16 = cap_gain16_shutter / cap_shutter; 214919a81c14SSteve Longerbeam } 215019a81c14SSteve Longerbeam } 215119a81c14SSteve Longerbeam 215219a81c14SSteve Longerbeam /* set capture gain */ 21533cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, cap_gain16); 215419a81c14SSteve Longerbeam if (ret) 215519a81c14SSteve Longerbeam return ret; 215619a81c14SSteve Longerbeam 215719a81c14SSteve Longerbeam /* write capture shutter */ 215819a81c14SSteve Longerbeam if (cap_shutter > (cap_vts - 4)) { 215919a81c14SSteve Longerbeam cap_vts = cap_shutter + 4; 216019a81c14SSteve Longerbeam ret = ov5640_set_vts(sensor, cap_vts); 216119a81c14SSteve Longerbeam if (ret < 0) 216219a81c14SSteve Longerbeam return ret; 216319a81c14SSteve Longerbeam } 216419a81c14SSteve Longerbeam 216519a81c14SSteve Longerbeam /* set exposure */ 21663cca8ef5SHugues Fruchet return ov5640_set_exposure(sensor, cap_shutter); 216719a81c14SSteve Longerbeam } 216819a81c14SSteve Longerbeam 216919a81c14SSteve Longerbeam /* 217019a81c14SSteve Longerbeam * if sensor changes inside scaling or subsampling 217119a81c14SSteve Longerbeam * change mode directly 217219a81c14SSteve Longerbeam */ 217319a81c14SSteve Longerbeam static int ov5640_set_mode_direct(struct ov5640_dev *sensor, 21743cca8ef5SHugues Fruchet const struct ov5640_mode_info *mode) 217519a81c14SSteve Longerbeam { 217641d8d7f5SHugues Fruchet if (!mode->reg_data) 217719a81c14SSteve Longerbeam return -EINVAL; 217819a81c14SSteve Longerbeam 217919a81c14SSteve Longerbeam /* Write capture setting */ 2180e4359019SJacopo Mondi ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size); 2181e4359019SJacopo Mondi return ov5640_set_timings(sensor, mode); 218219a81c14SSteve Longerbeam } 218319a81c14SSteve Longerbeam 2184985cdcb0SHugues Fruchet static int ov5640_set_mode(struct ov5640_dev *sensor) 218519a81c14SSteve Longerbeam { 218619a81c14SSteve Longerbeam const struct ov5640_mode_info *mode = sensor->current_mode; 2187985cdcb0SHugues Fruchet const struct ov5640_mode_info *orig_mode = sensor->last_mode; 218819a81c14SSteve Longerbeam enum ov5640_downsize_mode dn_mode, orig_dn_mode; 21893cca8ef5SHugues Fruchet bool auto_gain = sensor->ctrls.auto_gain->val == 1; 2190dc29a1c1SHugues Fruchet bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; 219119a81c14SSteve Longerbeam int ret; 219219a81c14SSteve Longerbeam 219319a81c14SSteve Longerbeam dn_mode = mode->dn_mode; 219419a81c14SSteve Longerbeam orig_dn_mode = orig_mode->dn_mode; 219519a81c14SSteve Longerbeam 219619a81c14SSteve Longerbeam /* auto gain and exposure must be turned off when changing modes */ 21973cca8ef5SHugues Fruchet if (auto_gain) { 21983cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, false); 219919a81c14SSteve Longerbeam if (ret) 220019a81c14SSteve Longerbeam return ret; 22013cca8ef5SHugues Fruchet } 2202bf4a4b51SMaxime Ripard 22033cca8ef5SHugues Fruchet if (auto_exp) { 2204dc29a1c1SHugues Fruchet ret = ov5640_set_autoexposure(sensor, false); 220519a81c14SSteve Longerbeam if (ret) 22063cca8ef5SHugues Fruchet goto restore_auto_gain; 22073cca8ef5SHugues Fruchet } 220819a81c14SSteve Longerbeam 22096c957ed7SJacopo Mondi if (ov5640_is_csi2(sensor)) 22106c957ed7SJacopo Mondi ret = ov5640_set_mipi_pclk(sensor); 22116c957ed7SJacopo Mondi else 22126c957ed7SJacopo Mondi ret = ov5640_set_dvp_pclk(sensor); 2213aa288248SMaxime Ripard if (ret < 0) 2214aa288248SMaxime Ripard return 0; 2215aa288248SMaxime Ripard 221619a81c14SSteve Longerbeam if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || 221719a81c14SSteve Longerbeam (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { 221819a81c14SSteve Longerbeam /* 221919a81c14SSteve Longerbeam * change between subsampling and scaling 22203cca8ef5SHugues Fruchet * go through exposure calculation 222119a81c14SSteve Longerbeam */ 222219a81c14SSteve Longerbeam ret = ov5640_set_mode_exposure_calc(sensor, mode); 222319a81c14SSteve Longerbeam } else { 222419a81c14SSteve Longerbeam /* 222519a81c14SSteve Longerbeam * change inside subsampling or scaling 222619a81c14SSteve Longerbeam * download firmware directly 222719a81c14SSteve Longerbeam */ 22283cca8ef5SHugues Fruchet ret = ov5640_set_mode_direct(sensor, mode); 222919a81c14SSteve Longerbeam } 223019a81c14SSteve Longerbeam if (ret < 0) 22313cca8ef5SHugues Fruchet goto restore_auto_exp_gain; 22323cca8ef5SHugues Fruchet 22333cca8ef5SHugues Fruchet /* restore auto gain and exposure */ 22343cca8ef5SHugues Fruchet if (auto_gain) 22353cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 22363cca8ef5SHugues Fruchet if (auto_exp) 22373cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 223819a81c14SSteve Longerbeam 2239ce85705aSHugues Fruchet ret = ov5640_set_binning(sensor, dn_mode != SCALING); 2240ce85705aSHugues Fruchet if (ret < 0) 2241ce85705aSHugues Fruchet return ret; 224219a81c14SSteve Longerbeam ret = ov5640_set_ae_target(sensor, sensor->ae_target); 224319a81c14SSteve Longerbeam if (ret < 0) 224419a81c14SSteve Longerbeam return ret; 224519a81c14SSteve Longerbeam ret = ov5640_get_light_freq(sensor); 224619a81c14SSteve Longerbeam if (ret < 0) 224719a81c14SSteve Longerbeam return ret; 224819a81c14SSteve Longerbeam ret = ov5640_set_bandingfilter(sensor); 224919a81c14SSteve Longerbeam if (ret < 0) 225019a81c14SSteve Longerbeam return ret; 225119a81c14SSteve Longerbeam ret = ov5640_set_virtual_channel(sensor); 225219a81c14SSteve Longerbeam if (ret < 0) 225319a81c14SSteve Longerbeam return ret; 225419a81c14SSteve Longerbeam 225519a81c14SSteve Longerbeam sensor->pending_mode_change = false; 2256985cdcb0SHugues Fruchet sensor->last_mode = mode; 225719a81c14SSteve Longerbeam 225819a81c14SSteve Longerbeam return 0; 22593cca8ef5SHugues Fruchet 22603cca8ef5SHugues Fruchet restore_auto_exp_gain: 22613cca8ef5SHugues Fruchet if (auto_exp) 22623cca8ef5SHugues Fruchet ov5640_set_autoexposure(sensor, true); 22633cca8ef5SHugues Fruchet restore_auto_gain: 22643cca8ef5SHugues Fruchet if (auto_gain) 22653cca8ef5SHugues Fruchet ov5640_set_autogain(sensor, true); 22663cca8ef5SHugues Fruchet 22673cca8ef5SHugues Fruchet return ret; 226819a81c14SSteve Longerbeam } 226919a81c14SSteve Longerbeam 227019ad26f9SAkinobu Mita static int ov5640_set_framefmt(struct ov5640_dev *sensor, 227119ad26f9SAkinobu Mita struct v4l2_mbus_framefmt *format); 227219ad26f9SAkinobu Mita 227319a81c14SSteve Longerbeam /* restore the last set video mode after chip power-on */ 227419a81c14SSteve Longerbeam static int ov5640_restore_mode(struct ov5640_dev *sensor) 227519a81c14SSteve Longerbeam { 227619a81c14SSteve Longerbeam int ret; 227719a81c14SSteve Longerbeam 227819a81c14SSteve Longerbeam /* first load the initial register values */ 2279e4359019SJacopo Mondi ov5640_load_regs(sensor, ov5640_init_setting, 2280e4359019SJacopo Mondi ARRAY_SIZE(ov5640_init_setting)); 228119a81c14SSteve Longerbeam 22828f57c2f8SMaxime Ripard ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, 22837851fe7aSMaxime Ripard (ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) | 22847851fe7aSMaxime Ripard ilog2(OV5640_SCLK_ROOT_DIV)); 22858f57c2f8SMaxime Ripard if (ret) 22868f57c2f8SMaxime Ripard return ret; 22878f57c2f8SMaxime Ripard 228819a81c14SSteve Longerbeam /* now restore the last capture mode */ 2289985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 229019ad26f9SAkinobu Mita if (ret < 0) 229119ad26f9SAkinobu Mita return ret; 229219ad26f9SAkinobu Mita 229319ad26f9SAkinobu Mita return ov5640_set_framefmt(sensor, &sensor->fmt); 229419a81c14SSteve Longerbeam } 229519a81c14SSteve Longerbeam 229619a81c14SSteve Longerbeam static void ov5640_power(struct ov5640_dev *sensor, bool enable) 229719a81c14SSteve Longerbeam { 22981fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); 229919a81c14SSteve Longerbeam } 230019a81c14SSteve Longerbeam 230119a81c14SSteve Longerbeam static void ov5640_reset(struct ov5640_dev *sensor) 230219a81c14SSteve Longerbeam { 230319a81c14SSteve Longerbeam if (!sensor->reset_gpio) 230419a81c14SSteve Longerbeam return; 230519a81c14SSteve Longerbeam 23061fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 230719a81c14SSteve Longerbeam 230819a81c14SSteve Longerbeam /* camera power cycle */ 230919a81c14SSteve Longerbeam ov5640_power(sensor, false); 231019a81c14SSteve Longerbeam usleep_range(5000, 10000); 231119a81c14SSteve Longerbeam ov5640_power(sensor, true); 231219a81c14SSteve Longerbeam usleep_range(5000, 10000); 231319a81c14SSteve Longerbeam 23141fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 1); 231519a81c14SSteve Longerbeam usleep_range(1000, 2000); 231619a81c14SSteve Longerbeam 23171fddc5daSHugues Fruchet gpiod_set_value_cansleep(sensor->reset_gpio, 0); 23181d4c41f3SLoic Poulain usleep_range(20000, 25000); 231919a81c14SSteve Longerbeam } 232019a81c14SSteve Longerbeam 23210f7acb52SHugues Fruchet static int ov5640_set_power_on(struct ov5640_dev *sensor) 232219a81c14SSteve Longerbeam { 23230f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 23240f7acb52SHugues Fruchet int ret; 232519a81c14SSteve Longerbeam 23260f7acb52SHugues Fruchet ret = clk_prepare_enable(sensor->xclk); 23270f7acb52SHugues Fruchet if (ret) { 23280f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable clock\n", 23290f7acb52SHugues Fruchet __func__); 23300f7acb52SHugues Fruchet return ret; 23310f7acb52SHugues Fruchet } 233219a81c14SSteve Longerbeam 233319a81c14SSteve Longerbeam ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, 233419a81c14SSteve Longerbeam sensor->supplies); 23350f7acb52SHugues Fruchet if (ret) { 23360f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to enable regulators\n", 23370f7acb52SHugues Fruchet __func__); 233819a81c14SSteve Longerbeam goto xclk_off; 23390f7acb52SHugues Fruchet } 234019a81c14SSteve Longerbeam 234119a81c14SSteve Longerbeam ov5640_reset(sensor); 234219a81c14SSteve Longerbeam ov5640_power(sensor, true); 234319a81c14SSteve Longerbeam 234419a81c14SSteve Longerbeam ret = ov5640_init_slave_id(sensor); 234519a81c14SSteve Longerbeam if (ret) 234619a81c14SSteve Longerbeam goto power_off; 234719a81c14SSteve Longerbeam 23480f7acb52SHugues Fruchet return 0; 23490f7acb52SHugues Fruchet 23500f7acb52SHugues Fruchet power_off: 23510f7acb52SHugues Fruchet ov5640_power(sensor, false); 23520f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 23530f7acb52SHugues Fruchet xclk_off: 23540f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 23550f7acb52SHugues Fruchet return ret; 23560f7acb52SHugues Fruchet } 23570f7acb52SHugues Fruchet 23580f7acb52SHugues Fruchet static void ov5640_set_power_off(struct ov5640_dev *sensor) 23590f7acb52SHugues Fruchet { 23600f7acb52SHugues Fruchet ov5640_power(sensor, false); 23610f7acb52SHugues Fruchet regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); 23620f7acb52SHugues Fruchet clk_disable_unprepare(sensor->xclk); 23630f7acb52SHugues Fruchet } 23640f7acb52SHugues Fruchet 2365b1751ae6SLad Prabhakar static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) 2366b1751ae6SLad Prabhakar { 2367b1751ae6SLad Prabhakar int ret; 2368b1751ae6SLad Prabhakar 2369b1751ae6SLad Prabhakar if (!on) { 2370b1751ae6SLad Prabhakar /* Reset MIPI bus settings to their default values. */ 2371b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2372b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04); 2373b1751ae6SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00); 2374b1751ae6SLad Prabhakar return 0; 2375b1751ae6SLad Prabhakar } 2376b1751ae6SLad Prabhakar 2377b1751ae6SLad Prabhakar /* 2378b1751ae6SLad Prabhakar * Power up MIPI HS Tx and LS Rx; 2 data lanes mode 2379b1751ae6SLad Prabhakar * 2380b1751ae6SLad Prabhakar * 0x300e = 0x40 2381b1751ae6SLad Prabhakar * [7:5] = 010 : 2 data lanes mode (see FIXME note in 2382b1751ae6SLad Prabhakar * "ov5640_set_stream_mipi()") 2383b1751ae6SLad Prabhakar * [4] = 0 : Power up MIPI HS Tx 2384b1751ae6SLad Prabhakar * [3] = 0 : Power up MIPI LS Rx 2385b1751ae6SLad Prabhakar * [2] = 0 : MIPI interface disabled 2386b1751ae6SLad Prabhakar */ 2387b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40); 2388b1751ae6SLad Prabhakar if (ret) 2389b1751ae6SLad Prabhakar return ret; 2390b1751ae6SLad Prabhakar 2391b1751ae6SLad Prabhakar /* 2392b1751ae6SLad Prabhakar * Gate clock and set LP11 in 'no packets mode' (idle) 2393b1751ae6SLad Prabhakar * 2394b1751ae6SLad Prabhakar * 0x4800 = 0x24 2395b1751ae6SLad Prabhakar * [5] = 1 : Gate clock when 'no packets' 2396b1751ae6SLad Prabhakar * [2] = 1 : MIPI bus in LP11 when 'no packets' 2397b1751ae6SLad Prabhakar */ 2398b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24); 2399b1751ae6SLad Prabhakar if (ret) 2400b1751ae6SLad Prabhakar return ret; 2401b1751ae6SLad Prabhakar 2402b1751ae6SLad Prabhakar /* 2403b1751ae6SLad Prabhakar * Set data lanes and clock in LP11 when 'sleeping' 2404b1751ae6SLad Prabhakar * 2405b1751ae6SLad Prabhakar * 0x3019 = 0x70 2406b1751ae6SLad Prabhakar * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping' 2407b1751ae6SLad Prabhakar * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping' 2408b1751ae6SLad Prabhakar * [4] = 1 : MIPI clock lane in LP11 when 'sleeping' 2409b1751ae6SLad Prabhakar */ 2410b1751ae6SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70); 2411b1751ae6SLad Prabhakar if (ret) 2412b1751ae6SLad Prabhakar return ret; 2413b1751ae6SLad Prabhakar 2414b1751ae6SLad Prabhakar /* Give lanes some time to coax into LP11 state. */ 2415b1751ae6SLad Prabhakar usleep_range(500, 1000); 2416b1751ae6SLad Prabhakar 2417b1751ae6SLad Prabhakar return 0; 2418b1751ae6SLad Prabhakar } 2419b1751ae6SLad Prabhakar 2420576f5d4bSLad Prabhakar static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on) 2421576f5d4bSLad Prabhakar { 2422311a6408SLad Prabhakar unsigned int flags = sensor->ep.bus.parallel.flags; 242368579b32SHugues Fruchet bool bt656 = sensor->ep.bus_type == V4L2_MBUS_BT656; 242468579b32SHugues Fruchet u8 polarities = 0; 2425576f5d4bSLad Prabhakar int ret; 2426576f5d4bSLad Prabhakar 2427576f5d4bSLad Prabhakar if (!on) { 2428576f5d4bSLad Prabhakar /* Reset settings to their default values. */ 242968579b32SHugues Fruchet ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 0x00); 2430311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58); 2431311a6408SLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20); 2432576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00); 2433576f5d4bSLad Prabhakar ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00); 2434576f5d4bSLad Prabhakar return 0; 2435576f5d4bSLad Prabhakar } 2436576f5d4bSLad Prabhakar 2437576f5d4bSLad Prabhakar /* 2438311a6408SLad Prabhakar * Note about parallel port configuration. 2439311a6408SLad Prabhakar * 2440311a6408SLad Prabhakar * When configured in parallel mode, the OV5640 will 2441311a6408SLad Prabhakar * output 10 bits data on DVP data lines [9:0]. 2442311a6408SLad Prabhakar * If only 8 bits data are wanted, the 8 bits data lines 2443311a6408SLad Prabhakar * of the camera interface must be physically connected 2444311a6408SLad Prabhakar * on the DVP data lines [9:2]. 2445311a6408SLad Prabhakar * 2446311a6408SLad Prabhakar * Control lines polarity can be configured through 2447311a6408SLad Prabhakar * devicetree endpoint control lines properties. 2448311a6408SLad Prabhakar * If no endpoint control lines properties are set, 2449311a6408SLad Prabhakar * polarity will be as below: 2450311a6408SLad Prabhakar * - VSYNC: active high 2451311a6408SLad Prabhakar * - HREF: active low 2452311a6408SLad Prabhakar * - PCLK: active low 245368579b32SHugues Fruchet * 245468579b32SHugues Fruchet * VSYNC & HREF are not configured if BT656 bus mode is selected 2455311a6408SLad Prabhakar */ 245668579b32SHugues Fruchet 245768579b32SHugues Fruchet /* 245868579b32SHugues Fruchet * BT656 embedded synchronization configuration 245968579b32SHugues Fruchet * 246068579b32SHugues Fruchet * CCIR656 CTRL00 246168579b32SHugues Fruchet * - [7]: SYNC code selection (0: auto generate sync code, 246268579b32SHugues Fruchet * 1: sync code from regs 0x4732-0x4735) 246368579b32SHugues Fruchet * - [6]: f value in CCIR656 SYNC code when fixed f value 246468579b32SHugues Fruchet * - [5]: Fixed f value 246568579b32SHugues Fruchet * - [4:3]: Blank toggle data options (00: data=1'h040/1'h200, 246668579b32SHugues Fruchet * 01: data from regs 0x4736-0x4738, 10: always keep 0) 246768579b32SHugues Fruchet * - [1]: Clip data disable 246868579b32SHugues Fruchet * - [0]: CCIR656 mode enable 246968579b32SHugues Fruchet * 247068579b32SHugues Fruchet * Default CCIR656 SAV/EAV mode with default codes 247168579b32SHugues Fruchet * SAV=0xff000080 & EAV=0xff00009d is enabled here with settings: 247268579b32SHugues Fruchet * - CCIR656 mode enable 247368579b32SHugues Fruchet * - auto generation of sync codes 247468579b32SHugues Fruchet * - blank toggle data 1'h040/1'h200 247568579b32SHugues Fruchet * - clip reserved data (0x00 & 0xff changed to 0x01 & 0xfe) 247668579b32SHugues Fruchet */ 247768579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00, 247868579b32SHugues Fruchet bt656 ? 0x01 : 0x00); 247968579b32SHugues Fruchet if (ret) 248068579b32SHugues Fruchet return ret; 248168579b32SHugues Fruchet 2482311a6408SLad Prabhakar /* 2483311a6408SLad Prabhakar * configure parallel port control lines polarity 2484311a6408SLad Prabhakar * 2485311a6408SLad Prabhakar * POLARITY CTRL0 2486311a6408SLad Prabhakar * - [5]: PCLK polarity (0: active low, 1: active high) 2487311a6408SLad Prabhakar * - [1]: HREF polarity (0: active low, 1: active high) 2488311a6408SLad Prabhakar * - [0]: VSYNC polarity (mismatch here between 2489311a6408SLad Prabhakar * datasheet and hardware, 0 is active high 2490311a6408SLad Prabhakar * and 1 is active low...) 2491311a6408SLad Prabhakar */ 249268579b32SHugues Fruchet if (!bt656) { 2493311a6408SLad Prabhakar if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 249468579b32SHugues Fruchet polarities |= BIT(1); 2495311a6408SLad Prabhakar if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 249668579b32SHugues Fruchet polarities |= BIT(0); 249768579b32SHugues Fruchet } 249868579b32SHugues Fruchet if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 249968579b32SHugues Fruchet polarities |= BIT(5); 2500311a6408SLad Prabhakar 250168579b32SHugues Fruchet ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, polarities); 2502311a6408SLad Prabhakar if (ret) 2503311a6408SLad Prabhakar return ret; 2504311a6408SLad Prabhakar 2505311a6408SLad Prabhakar /* 250668579b32SHugues Fruchet * powerdown MIPI TX/RX PHY & enable DVP 2507311a6408SLad Prabhakar * 2508311a6408SLad Prabhakar * MIPI CONTROL 00 250968579b32SHugues Fruchet * [4] = 1 : Power down MIPI HS Tx 251068579b32SHugues Fruchet * [3] = 1 : Power down MIPI LS Rx 251168579b32SHugues Fruchet * [2] = 0 : DVP enable (MIPI disable) 2512311a6408SLad Prabhakar */ 2513311a6408SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18); 2514311a6408SLad Prabhakar if (ret) 2515311a6408SLad Prabhakar return ret; 2516311a6408SLad Prabhakar 2517311a6408SLad Prabhakar /* 2518576f5d4bSLad Prabhakar * enable VSYNC/HREF/PCLK DVP control lines 2519576f5d4bSLad Prabhakar * & D[9:6] DVP data lines 2520576f5d4bSLad Prabhakar * 2521576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 01 2522576f5d4bSLad Prabhakar * - 6: VSYNC output enable 2523576f5d4bSLad Prabhakar * - 5: HREF output enable 2524576f5d4bSLad Prabhakar * - 4: PCLK output enable 2525576f5d4bSLad Prabhakar * - [3:0]: D[9:6] output enable 2526576f5d4bSLad Prabhakar */ 25274039b037SLad Prabhakar ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 252868579b32SHugues Fruchet bt656 ? 0x1f : 0x7f); 2529576f5d4bSLad Prabhakar if (ret) 2530576f5d4bSLad Prabhakar return ret; 2531576f5d4bSLad Prabhakar 2532576f5d4bSLad Prabhakar /* 2533576f5d4bSLad Prabhakar * enable D[5:0] DVP data lines 2534576f5d4bSLad Prabhakar * 2535576f5d4bSLad Prabhakar * PAD OUTPUT ENABLE 02 2536576f5d4bSLad Prabhakar * - [7:2]: D[5:0] output enable 2537576f5d4bSLad Prabhakar */ 2538576f5d4bSLad Prabhakar return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc); 2539576f5d4bSLad Prabhakar } 2540576f5d4bSLad Prabhakar 25410f7acb52SHugues Fruchet static int ov5640_set_power(struct ov5640_dev *sensor, bool on) 25420f7acb52SHugues Fruchet { 25430f7acb52SHugues Fruchet int ret = 0; 25440f7acb52SHugues Fruchet 25450f7acb52SHugues Fruchet if (on) { 25460f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 25470f7acb52SHugues Fruchet if (ret) 25480f7acb52SHugues Fruchet return ret; 25490f7acb52SHugues Fruchet 255019a81c14SSteve Longerbeam ret = ov5640_restore_mode(sensor); 255119a81c14SSteve Longerbeam if (ret) 255219a81c14SSteve Longerbeam goto power_off; 2553b1751ae6SLad Prabhakar } 255419a81c14SSteve Longerbeam 2555576f5d4bSLad Prabhakar if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) 2556b1751ae6SLad Prabhakar ret = ov5640_set_power_mipi(sensor, on); 2557576f5d4bSLad Prabhakar else 2558576f5d4bSLad Prabhakar ret = ov5640_set_power_dvp(sensor, on); 2559b1751ae6SLad Prabhakar if (ret) 2560b1751ae6SLad Prabhakar goto power_off; 2561aa4bb8b8SJacopo Mondi 2562b1751ae6SLad Prabhakar if (!on) 2563aa4bb8b8SJacopo Mondi ov5640_set_power_off(sensor); 256419a81c14SSteve Longerbeam 256519a81c14SSteve Longerbeam return 0; 256619a81c14SSteve Longerbeam 256719a81c14SSteve Longerbeam power_off: 25680f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 256919a81c14SSteve Longerbeam return ret; 257019a81c14SSteve Longerbeam } 257119a81c14SSteve Longerbeam 257219a81c14SSteve Longerbeam /* --------------- Subdev Operations --------------- */ 257319a81c14SSteve Longerbeam 257419a81c14SSteve Longerbeam static int ov5640_s_power(struct v4l2_subdev *sd, int on) 257519a81c14SSteve Longerbeam { 257619a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 257719a81c14SSteve Longerbeam int ret = 0; 257819a81c14SSteve Longerbeam 257919a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 258019a81c14SSteve Longerbeam 258119a81c14SSteve Longerbeam /* 258219a81c14SSteve Longerbeam * If the power count is modified from 0 to != 0 or from != 0 to 0, 258319a81c14SSteve Longerbeam * update the power state. 258419a81c14SSteve Longerbeam */ 258519a81c14SSteve Longerbeam if (sensor->power_count == !on) { 258619a81c14SSteve Longerbeam ret = ov5640_set_power(sensor, !!on); 258719a81c14SSteve Longerbeam if (ret) 258819a81c14SSteve Longerbeam goto out; 258919a81c14SSteve Longerbeam } 259019a81c14SSteve Longerbeam 259119a81c14SSteve Longerbeam /* Update the power count. */ 259219a81c14SSteve Longerbeam sensor->power_count += on ? 1 : -1; 259319a81c14SSteve Longerbeam WARN_ON(sensor->power_count < 0); 259419a81c14SSteve Longerbeam out: 259519a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 259619a81c14SSteve Longerbeam 259719a81c14SSteve Longerbeam if (on && !ret && sensor->power_count == 1) { 259819a81c14SSteve Longerbeam /* restore controls */ 259919a81c14SSteve Longerbeam ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); 260019a81c14SSteve Longerbeam } 260119a81c14SSteve Longerbeam 260219a81c14SSteve Longerbeam return ret; 260319a81c14SSteve Longerbeam } 260419a81c14SSteve Longerbeam 260519a81c14SSteve Longerbeam static int ov5640_try_frame_interval(struct ov5640_dev *sensor, 260619a81c14SSteve Longerbeam struct v4l2_fract *fi, 260719a81c14SSteve Longerbeam u32 width, u32 height) 260819a81c14SSteve Longerbeam { 260919a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 26106530a5ebSJagan Teki enum ov5640_frame_rate rate = OV5640_15_FPS; 2611f6cc192fSMaxime Ripard int minfps, maxfps, best_fps, fps; 2612f6cc192fSMaxime Ripard int i; 261319a81c14SSteve Longerbeam 261419a81c14SSteve Longerbeam minfps = ov5640_framerates[OV5640_15_FPS]; 2615e823fb16SMaxime Ripard maxfps = ov5640_framerates[OV5640_60_FPS]; 261619a81c14SSteve Longerbeam 261719a81c14SSteve Longerbeam if (fi->numerator == 0) { 261819a81c14SSteve Longerbeam fi->denominator = maxfps; 261919a81c14SSteve Longerbeam fi->numerator = 1; 2620e823fb16SMaxime Ripard rate = OV5640_60_FPS; 2621e823fb16SMaxime Ripard goto find_mode; 262219a81c14SSteve Longerbeam } 262319a81c14SSteve Longerbeam 2624f6cc192fSMaxime Ripard fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator), 2625f6cc192fSMaxime Ripard minfps, maxfps); 2626f6cc192fSMaxime Ripard 2627f6cc192fSMaxime Ripard best_fps = minfps; 2628f6cc192fSMaxime Ripard for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) { 2629f6cc192fSMaxime Ripard int curr_fps = ov5640_framerates[i]; 2630f6cc192fSMaxime Ripard 2631f6cc192fSMaxime Ripard if (abs(curr_fps - fps) < abs(best_fps - fps)) { 2632f6cc192fSMaxime Ripard best_fps = curr_fps; 2633f6cc192fSMaxime Ripard rate = i; 2634f6cc192fSMaxime Ripard } 2635f6cc192fSMaxime Ripard } 263619a81c14SSteve Longerbeam 263719a81c14SSteve Longerbeam fi->numerator = 1; 2638f6cc192fSMaxime Ripard fi->denominator = best_fps; 263919a81c14SSteve Longerbeam 2640e823fb16SMaxime Ripard find_mode: 26415a3ad937SMaxime Ripard mode = ov5640_find_mode(sensor, rate, width, height, false); 26425a3ad937SMaxime Ripard return mode ? rate : -EINVAL; 264319a81c14SSteve Longerbeam } 264419a81c14SSteve Longerbeam 264519a81c14SSteve Longerbeam static int ov5640_get_fmt(struct v4l2_subdev *sd, 26460d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 264719a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 264819a81c14SSteve Longerbeam { 264919a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 265019a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt; 265119a81c14SSteve Longerbeam 265219a81c14SSteve Longerbeam if (format->pad != 0) 265319a81c14SSteve Longerbeam return -EINVAL; 265419a81c14SSteve Longerbeam 265519a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 265619a81c14SSteve Longerbeam 265719a81c14SSteve Longerbeam if (format->which == V4L2_SUBDEV_FORMAT_TRY) 26580d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 265919a81c14SSteve Longerbeam format->pad); 266019a81c14SSteve Longerbeam else 266119a81c14SSteve Longerbeam fmt = &sensor->fmt; 266219a81c14SSteve Longerbeam 266319a81c14SSteve Longerbeam format->format = *fmt; 266419a81c14SSteve Longerbeam 266519a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 266619a81c14SSteve Longerbeam 266719a81c14SSteve Longerbeam return 0; 266819a81c14SSteve Longerbeam } 266919a81c14SSteve Longerbeam 267019a81c14SSteve Longerbeam static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, 267119a81c14SSteve Longerbeam struct v4l2_mbus_framefmt *fmt, 267219a81c14SSteve Longerbeam enum ov5640_frame_rate fr, 267319a81c14SSteve Longerbeam const struct ov5640_mode_info **new_mode) 267419a81c14SSteve Longerbeam { 267519a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 267619a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 2677e3ee691dSHugues Fruchet int i; 267819a81c14SSteve Longerbeam 267919a81c14SSteve Longerbeam mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); 268019a81c14SSteve Longerbeam if (!mode) 268119a81c14SSteve Longerbeam return -EINVAL; 26825113d5b3SJacopo Mondi fmt->width = mode->width; 26835113d5b3SJacopo Mondi fmt->height = mode->height; 268419a81c14SSteve Longerbeam 268519a81c14SSteve Longerbeam if (new_mode) 268619a81c14SSteve Longerbeam *new_mode = mode; 2687e3ee691dSHugues Fruchet 2688e3ee691dSHugues Fruchet for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) 2689e3ee691dSHugues Fruchet if (ov5640_formats[i].code == fmt->code) 2690e3ee691dSHugues Fruchet break; 2691e3ee691dSHugues Fruchet if (i >= ARRAY_SIZE(ov5640_formats)) 2692e6441fdeSHugues Fruchet i = 0; 2693e6441fdeSHugues Fruchet 2694e6441fdeSHugues Fruchet fmt->code = ov5640_formats[i].code; 2695e6441fdeSHugues Fruchet fmt->colorspace = ov5640_formats[i].colorspace; 2696e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 2697e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 2698e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 2699e3ee691dSHugues Fruchet 270019a81c14SSteve Longerbeam return 0; 270119a81c14SSteve Longerbeam } 270219a81c14SSteve Longerbeam 27033c28588fSJacopo Mondi static int ov5640_update_pixel_rate(struct ov5640_dev *sensor) 27043c28588fSJacopo Mondi { 27053c28588fSJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 27063c28588fSJacopo Mondi enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate; 27073c28588fSJacopo Mondi struct v4l2_mbus_framefmt *fmt = &sensor->fmt; 270832979f67SJacopo Mondi const struct ov5640_timings *timings; 2709*bce93b82SJacopo Mondi s32 exposure_val, exposure_max; 271032979f67SJacopo Mondi unsigned int hblank; 27113c28588fSJacopo Mondi unsigned int i = 0; 27123c28588fSJacopo Mondi u32 pixel_rate; 27133c28588fSJacopo Mondi s64 link_freq; 27143c28588fSJacopo Mondi u32 num_lanes; 27153c28588fSJacopo Mondi u32 bpp; 27163c28588fSJacopo Mondi 27173c28588fSJacopo Mondi /* 27183c28588fSJacopo Mondi * Update the pixel rate control value. 27193c28588fSJacopo Mondi * 27203c28588fSJacopo Mondi * For DVP mode, maintain the pixel rate calculation using fixed FPS. 27213c28588fSJacopo Mondi */ 27223c28588fSJacopo Mondi if (!ov5640_is_csi2(sensor)) { 27233c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 27243c28588fSJacopo Mondi ov5640_calc_pixel_rate(sensor)); 27253c28588fSJacopo Mondi 27263c28588fSJacopo Mondi return 0; 27273c28588fSJacopo Mondi } 27283c28588fSJacopo Mondi 27293c28588fSJacopo Mondi /* 27303c28588fSJacopo Mondi * The MIPI CSI-2 link frequency should comply with the CSI-2 27313c28588fSJacopo Mondi * specification and be lower than 1GHz. 27323c28588fSJacopo Mondi * 27333c28588fSJacopo Mondi * Start from the suggested pixel_rate for the current mode and 27343c28588fSJacopo Mondi * progressively slow it down if it exceeds 1GHz. 27353c28588fSJacopo Mondi */ 27363c28588fSJacopo Mondi num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes; 27373c28588fSJacopo Mondi bpp = ov5640_code_to_bpp(fmt->code); 27383c28588fSJacopo Mondi do { 27393c28588fSJacopo Mondi pixel_rate = ov5640_pixel_rates[pixel_rate_id]; 27403c28588fSJacopo Mondi link_freq = pixel_rate * bpp / (2 * num_lanes); 27413c28588fSJacopo Mondi } while (link_freq >= 1000000000U && 27423c28588fSJacopo Mondi ++pixel_rate_id < OV5640_NUM_PIXEL_RATES); 27433c28588fSJacopo Mondi 27443c28588fSJacopo Mondi sensor->current_link_freq = link_freq; 27453c28588fSJacopo Mondi 27463c28588fSJacopo Mondi /* 27473c28588fSJacopo Mondi * Higher link rates require the clock tree to be programmed with 27483c28588fSJacopo Mondi * 'mipi_div' = 1; this has the effect of halving the actual output 27493c28588fSJacopo Mondi * pixel rate in the MIPI domain. 27503c28588fSJacopo Mondi * 27513c28588fSJacopo Mondi * Adjust the pixel rate and link frequency control value to report it 27523c28588fSJacopo Mondi * correctly to userspace. 27533c28588fSJacopo Mondi */ 27543c28588fSJacopo Mondi if (link_freq > OV5640_LINK_RATE_MAX) { 27553c28588fSJacopo Mondi pixel_rate /= 2; 27563c28588fSJacopo Mondi link_freq /= 2; 27573c28588fSJacopo Mondi } 27583c28588fSJacopo Mondi 27593c28588fSJacopo Mondi for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) { 27603c28588fSJacopo Mondi if (ov5640_csi2_link_freqs[i] == link_freq) 27613c28588fSJacopo Mondi break; 27623c28588fSJacopo Mondi } 27633c28588fSJacopo Mondi WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs)); 27643c28588fSJacopo Mondi 27653c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate); 27663c28588fSJacopo Mondi __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i); 27673c28588fSJacopo Mondi 276832979f67SJacopo Mondi timings = ov5640_timings(sensor, mode); 276932979f67SJacopo Mondi hblank = timings->htot - mode->width; 277032979f67SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.hblank, 277132979f67SJacopo Mondi hblank, hblank, 1, hblank); 277232979f67SJacopo Mondi 2773*bce93b82SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK, 2774*bce93b82SJacopo Mondi OV5640_MAX_VTS - mode->height, 1, 2775*bce93b82SJacopo Mondi timings->vblank_def); 2776*bce93b82SJacopo Mondi __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, timings->vblank_def); 2777*bce93b82SJacopo Mondi 2778*bce93b82SJacopo Mondi exposure_max = timings->crop.height + timings->vblank_def - 4; 2779*bce93b82SJacopo Mondi exposure_val = clamp_t(s32, sensor->ctrls.exposure->val, 2780*bce93b82SJacopo Mondi sensor->ctrls.exposure->minimum, 2781*bce93b82SJacopo Mondi exposure_max); 2782*bce93b82SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 2783*bce93b82SJacopo Mondi sensor->ctrls.exposure->minimum, 2784*bce93b82SJacopo Mondi exposure_max, 1, exposure_val); 2785*bce93b82SJacopo Mondi 27863c28588fSJacopo Mondi return 0; 27873c28588fSJacopo Mondi } 27883c28588fSJacopo Mondi 278919a81c14SSteve Longerbeam static int ov5640_set_fmt(struct v4l2_subdev *sd, 27900d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 279119a81c14SSteve Longerbeam struct v4l2_subdev_format *format) 279219a81c14SSteve Longerbeam { 279319a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 279419a81c14SSteve Longerbeam const struct ov5640_mode_info *new_mode; 2795e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *mbus_fmt = &format->format; 279619a81c14SSteve Longerbeam int ret; 279719a81c14SSteve Longerbeam 279819a81c14SSteve Longerbeam if (format->pad != 0) 279919a81c14SSteve Longerbeam return -EINVAL; 280019a81c14SSteve Longerbeam 280119a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 280219a81c14SSteve Longerbeam 280319a81c14SSteve Longerbeam if (sensor->streaming) { 280419a81c14SSteve Longerbeam ret = -EBUSY; 280519a81c14SSteve Longerbeam goto out; 280619a81c14SSteve Longerbeam } 280719a81c14SSteve Longerbeam 2808e6441fdeSHugues Fruchet ret = ov5640_try_fmt_internal(sd, mbus_fmt, 280919a81c14SSteve Longerbeam sensor->current_fr, &new_mode); 281019a81c14SSteve Longerbeam if (ret) 281119a81c14SSteve Longerbeam goto out; 281219a81c14SSteve Longerbeam 2813e738f5ddSMirela Rabulea if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 2814e738f5ddSMirela Rabulea *v4l2_subdev_get_try_format(sd, sd_state, 0) = *mbus_fmt; 2815e738f5ddSMirela Rabulea goto out; 2816e738f5ddSMirela Rabulea } 281719a81c14SSteve Longerbeam 28186949d864SHugues Fruchet if (new_mode != sensor->current_mode) { 281919a81c14SSteve Longerbeam sensor->current_mode = new_mode; 282019a81c14SSteve Longerbeam sensor->pending_mode_change = true; 28216949d864SHugues Fruchet } 282207115449SJacopo Mondi if (mbus_fmt->code != sensor->fmt.code) 2823fb98e29fSHugues Fruchet sensor->pending_fmt_change = true; 282407115449SJacopo Mondi 2825e738f5ddSMirela Rabulea /* update format even if code is unchanged, resolution might change */ 2826e738f5ddSMirela Rabulea sensor->fmt = *mbus_fmt; 2827e738f5ddSMirela Rabulea 28283c28588fSJacopo Mondi ov5640_update_pixel_rate(sensor); 28293c28588fSJacopo Mondi 283019a81c14SSteve Longerbeam out: 283119a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 283219a81c14SSteve Longerbeam return ret; 283319a81c14SSteve Longerbeam } 283419a81c14SSteve Longerbeam 2835e3ee691dSHugues Fruchet static int ov5640_set_framefmt(struct ov5640_dev *sensor, 2836e3ee691dSHugues Fruchet struct v4l2_mbus_framefmt *format) 2837e3ee691dSHugues Fruchet { 2838e3ee691dSHugues Fruchet int ret = 0; 2839d47c4126SHugues Fruchet bool is_jpeg = false; 2840b7ed3abdSLoic Poulain u8 fmt, mux; 2841e3ee691dSHugues Fruchet 2842e3ee691dSHugues Fruchet switch (format->code) { 28431536fbdbSXavier Roumegue case MEDIA_BUS_FMT_UYVY8_1X16: 2844e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_UYVY8_2X8: 2845e3ee691dSHugues Fruchet /* YUV422, UYVY */ 2846b7ed3abdSLoic Poulain fmt = 0x3f; 2847b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2848e3ee691dSHugues Fruchet break; 28491536fbdbSXavier Roumegue case MEDIA_BUS_FMT_YUYV8_1X16: 2850e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_YUYV8_2X8: 2851e3ee691dSHugues Fruchet /* YUV422, YUYV */ 2852b7ed3abdSLoic Poulain fmt = 0x30; 2853b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2854e3ee691dSHugues Fruchet break; 2855e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_LE: 2856e3ee691dSHugues Fruchet /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ 2857b7ed3abdSLoic Poulain fmt = 0x6F; 2858b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RGB; 2859e3ee691dSHugues Fruchet break; 2860e3ee691dSHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_BE: 2861e3ee691dSHugues Fruchet /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ 2862b7ed3abdSLoic Poulain fmt = 0x61; 2863b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RGB; 2864e3ee691dSHugues Fruchet break; 2865d47c4126SHugues Fruchet case MEDIA_BUS_FMT_JPEG_1X8: 2866d47c4126SHugues Fruchet /* YUV422, YUYV */ 2867b7ed3abdSLoic Poulain fmt = 0x30; 2868b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_YUV422; 2869d47c4126SHugues Fruchet is_jpeg = true; 2870d47c4126SHugues Fruchet break; 2871b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SBGGR8_1X8: 2872b7ed3abdSLoic Poulain /* Raw, BGBG... / GRGR... */ 2873b7ed3abdSLoic Poulain fmt = 0x00; 2874b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2875b7ed3abdSLoic Poulain break; 2876b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SGBRG8_1X8: 2877b7ed3abdSLoic Poulain /* Raw bayer, GBGB... / RGRG... */ 2878b7ed3abdSLoic Poulain fmt = 0x01; 2879b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2880b7ed3abdSLoic Poulain break; 2881b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SGRBG8_1X8: 2882b7ed3abdSLoic Poulain /* Raw bayer, GRGR... / BGBG... */ 2883b7ed3abdSLoic Poulain fmt = 0x02; 2884b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2885b7ed3abdSLoic Poulain break; 2886b7ed3abdSLoic Poulain case MEDIA_BUS_FMT_SRGGB8_1X8: 2887b7ed3abdSLoic Poulain /* Raw bayer, RGRG... / GBGB... */ 2888b7ed3abdSLoic Poulain fmt = 0x03; 2889b7ed3abdSLoic Poulain mux = OV5640_FMT_MUX_RAW_DPC; 2890b7ed3abdSLoic Poulain break; 2891e3ee691dSHugues Fruchet default: 2892e3ee691dSHugues Fruchet return -EINVAL; 2893e3ee691dSHugues Fruchet } 2894e3ee691dSHugues Fruchet 2895e3ee691dSHugues Fruchet /* FORMAT CONTROL00: YUV and RGB formatting */ 2896b7ed3abdSLoic Poulain ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt); 2897e3ee691dSHugues Fruchet if (ret) 2898e3ee691dSHugues Fruchet return ret; 2899e3ee691dSHugues Fruchet 2900e3ee691dSHugues Fruchet /* FORMAT MUX CONTROL: ISP YUV or RGB */ 2901b7ed3abdSLoic Poulain ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux); 2902d47c4126SHugues Fruchet if (ret) 2903d47c4126SHugues Fruchet return ret; 2904d47c4126SHugues Fruchet 2905d47c4126SHugues Fruchet /* 2906d47c4126SHugues Fruchet * TIMING TC REG21: 2907d47c4126SHugues Fruchet * - [5]: JPEG enable 2908d47c4126SHugues Fruchet */ 2909d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 2910d47c4126SHugues Fruchet BIT(5), is_jpeg ? BIT(5) : 0); 2911d47c4126SHugues Fruchet if (ret) 2912d47c4126SHugues Fruchet return ret; 2913d47c4126SHugues Fruchet 2914d47c4126SHugues Fruchet /* 2915d47c4126SHugues Fruchet * SYSTEM RESET02: 2916d47c4126SHugues Fruchet * - [4]: Reset JFIFO 2917d47c4126SHugues Fruchet * - [3]: Reset SFIFO 2918d47c4126SHugues Fruchet * - [2]: Reset JPEG 2919d47c4126SHugues Fruchet */ 2920d47c4126SHugues Fruchet ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_RESET02, 2921d47c4126SHugues Fruchet BIT(4) | BIT(3) | BIT(2), 2922d47c4126SHugues Fruchet is_jpeg ? 0 : (BIT(4) | BIT(3) | BIT(2))); 2923d47c4126SHugues Fruchet if (ret) 2924d47c4126SHugues Fruchet return ret; 2925d47c4126SHugues Fruchet 2926d47c4126SHugues Fruchet /* 2927d47c4126SHugues Fruchet * CLOCK ENABLE02: 2928d47c4126SHugues Fruchet * - [5]: Enable JPEG 2x clock 2929d47c4126SHugues Fruchet * - [3]: Enable JPEG clock 2930d47c4126SHugues Fruchet */ 2931d47c4126SHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE02, 2932d47c4126SHugues Fruchet BIT(5) | BIT(3), 2933d47c4126SHugues Fruchet is_jpeg ? (BIT(5) | BIT(3)) : 0); 2934e3ee691dSHugues Fruchet } 293519a81c14SSteve Longerbeam 293619a81c14SSteve Longerbeam /* 293719a81c14SSteve Longerbeam * Sensor Controls. 293819a81c14SSteve Longerbeam */ 293919a81c14SSteve Longerbeam 294019a81c14SSteve Longerbeam static int ov5640_set_ctrl_hue(struct ov5640_dev *sensor, int value) 294119a81c14SSteve Longerbeam { 294219a81c14SSteve Longerbeam int ret; 294319a81c14SSteve Longerbeam 294419a81c14SSteve Longerbeam if (value) { 294519a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 294619a81c14SSteve Longerbeam BIT(0), BIT(0)); 294719a81c14SSteve Longerbeam if (ret) 294819a81c14SSteve Longerbeam return ret; 294919a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_SDE_CTRL1, value); 295019a81c14SSteve Longerbeam } else { 295119a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(0), 0); 295219a81c14SSteve Longerbeam } 295319a81c14SSteve Longerbeam 295419a81c14SSteve Longerbeam return ret; 295519a81c14SSteve Longerbeam } 295619a81c14SSteve Longerbeam 295719a81c14SSteve Longerbeam static int ov5640_set_ctrl_contrast(struct ov5640_dev *sensor, int value) 295819a81c14SSteve Longerbeam { 295919a81c14SSteve Longerbeam int ret; 296019a81c14SSteve Longerbeam 296119a81c14SSteve Longerbeam if (value) { 296219a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 296319a81c14SSteve Longerbeam BIT(2), BIT(2)); 296419a81c14SSteve Longerbeam if (ret) 296519a81c14SSteve Longerbeam return ret; 296619a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL5, 296719a81c14SSteve Longerbeam value & 0xff); 296819a81c14SSteve Longerbeam } else { 296919a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(2), 0); 297019a81c14SSteve Longerbeam } 297119a81c14SSteve Longerbeam 297219a81c14SSteve Longerbeam return ret; 297319a81c14SSteve Longerbeam } 297419a81c14SSteve Longerbeam 297519a81c14SSteve Longerbeam static int ov5640_set_ctrl_saturation(struct ov5640_dev *sensor, int value) 297619a81c14SSteve Longerbeam { 297719a81c14SSteve Longerbeam int ret; 297819a81c14SSteve Longerbeam 297919a81c14SSteve Longerbeam if (value) { 298019a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, 298119a81c14SSteve Longerbeam BIT(1), BIT(1)); 298219a81c14SSteve Longerbeam if (ret) 298319a81c14SSteve Longerbeam return ret; 298419a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL3, 298519a81c14SSteve Longerbeam value & 0xff); 298619a81c14SSteve Longerbeam if (ret) 298719a81c14SSteve Longerbeam return ret; 298819a81c14SSteve Longerbeam ret = ov5640_write_reg(sensor, OV5640_REG_SDE_CTRL4, 298919a81c14SSteve Longerbeam value & 0xff); 299019a81c14SSteve Longerbeam } else { 299119a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_SDE_CTRL0, BIT(1), 0); 299219a81c14SSteve Longerbeam } 299319a81c14SSteve Longerbeam 299419a81c14SSteve Longerbeam return ret; 299519a81c14SSteve Longerbeam } 299619a81c14SSteve Longerbeam 299719a81c14SSteve Longerbeam static int ov5640_set_ctrl_white_balance(struct ov5640_dev *sensor, int awb) 299819a81c14SSteve Longerbeam { 299919a81c14SSteve Longerbeam int ret; 300019a81c14SSteve Longerbeam 300119a81c14SSteve Longerbeam ret = ov5640_mod_reg(sensor, OV5640_REG_AWB_MANUAL_CTRL, 300219a81c14SSteve Longerbeam BIT(0), awb ? 0 : 1); 300319a81c14SSteve Longerbeam if (ret) 300419a81c14SSteve Longerbeam return ret; 300519a81c14SSteve Longerbeam 300619a81c14SSteve Longerbeam if (!awb) { 300719a81c14SSteve Longerbeam u16 red = (u16)sensor->ctrls.red_balance->val; 300819a81c14SSteve Longerbeam u16 blue = (u16)sensor->ctrls.blue_balance->val; 300919a81c14SSteve Longerbeam 301019a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_R_GAIN, red); 301119a81c14SSteve Longerbeam if (ret) 301219a81c14SSteve Longerbeam return ret; 301319a81c14SSteve Longerbeam ret = ov5640_write_reg16(sensor, OV5640_REG_AWB_B_GAIN, blue); 301419a81c14SSteve Longerbeam } 301519a81c14SSteve Longerbeam 301619a81c14SSteve Longerbeam return ret; 301719a81c14SSteve Longerbeam } 301819a81c14SSteve Longerbeam 30193cca8ef5SHugues Fruchet static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, 30203cca8ef5SHugues Fruchet enum v4l2_exposure_auto_type auto_exposure) 302119a81c14SSteve Longerbeam { 302219a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 30233cca8ef5SHugues Fruchet bool auto_exp = (auto_exposure == V4L2_EXPOSURE_AUTO); 302419a81c14SSteve Longerbeam int ret = 0; 302519a81c14SSteve Longerbeam 302619a81c14SSteve Longerbeam if (ctrls->auto_exp->is_new) { 30273cca8ef5SHugues Fruchet ret = ov5640_set_autoexposure(sensor, auto_exp); 302819a81c14SSteve Longerbeam if (ret) 302919a81c14SSteve Longerbeam return ret; 303019a81c14SSteve Longerbeam } 303119a81c14SSteve Longerbeam 30323cca8ef5SHugues Fruchet if (!auto_exp && ctrls->exposure->is_new) { 303319a81c14SSteve Longerbeam u16 max_exp; 303419a81c14SSteve Longerbeam 303519a81c14SSteve Longerbeam ret = ov5640_read_reg16(sensor, OV5640_REG_AEC_PK_VTS, 303619a81c14SSteve Longerbeam &max_exp); 303719a81c14SSteve Longerbeam if (ret) 303819a81c14SSteve Longerbeam return ret; 303919a81c14SSteve Longerbeam ret = ov5640_get_vts(sensor); 304019a81c14SSteve Longerbeam if (ret < 0) 304119a81c14SSteve Longerbeam return ret; 304219a81c14SSteve Longerbeam max_exp += ret; 30436146fde3SHugues Fruchet ret = 0; 304419a81c14SSteve Longerbeam 304519a81c14SSteve Longerbeam if (ctrls->exposure->val < max_exp) 304619a81c14SSteve Longerbeam ret = ov5640_set_exposure(sensor, ctrls->exposure->val); 304719a81c14SSteve Longerbeam } 304819a81c14SSteve Longerbeam 304919a81c14SSteve Longerbeam return ret; 305019a81c14SSteve Longerbeam } 305119a81c14SSteve Longerbeam 30523cca8ef5SHugues Fruchet static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) 305319a81c14SSteve Longerbeam { 305419a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 305519a81c14SSteve Longerbeam int ret = 0; 305619a81c14SSteve Longerbeam 305719a81c14SSteve Longerbeam if (ctrls->auto_gain->is_new) { 30583cca8ef5SHugues Fruchet ret = ov5640_set_autogain(sensor, auto_gain); 305919a81c14SSteve Longerbeam if (ret) 306019a81c14SSteve Longerbeam return ret; 306119a81c14SSteve Longerbeam } 306219a81c14SSteve Longerbeam 30633cca8ef5SHugues Fruchet if (!auto_gain && ctrls->gain->is_new) 30643cca8ef5SHugues Fruchet ret = ov5640_set_gain(sensor, ctrls->gain->val); 306519a81c14SSteve Longerbeam 306619a81c14SSteve Longerbeam return ret; 306719a81c14SSteve Longerbeam } 306819a81c14SSteve Longerbeam 30699f6d7bacSChen-Yu Tsai static const char * const test_pattern_menu[] = { 30709f6d7bacSChen-Yu Tsai "Disabled", 30719f6d7bacSChen-Yu Tsai "Color bars", 3072bddc5cdfSChen-Yu Tsai "Color bars w/ rolling bar", 3073bddc5cdfSChen-Yu Tsai "Color squares", 3074bddc5cdfSChen-Yu Tsai "Color squares w/ rolling bar", 30759f6d7bacSChen-Yu Tsai }; 30769f6d7bacSChen-Yu Tsai 3077a0c29afbSChen-Yu Tsai #define OV5640_TEST_ENABLE BIT(7) 3078a0c29afbSChen-Yu Tsai #define OV5640_TEST_ROLLING BIT(6) /* rolling horizontal bar */ 3079a0c29afbSChen-Yu Tsai #define OV5640_TEST_TRANSPARENT BIT(5) 3080a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE_BW BIT(4) /* black & white squares */ 3081a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_STANDARD (0 << 2) 3082a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_1 (1 << 2) 3083a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_HOR_CHANGE (2 << 2) 3084a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR_VERT_CHANGE_2 (3 << 2) 3085a0c29afbSChen-Yu Tsai #define OV5640_TEST_BAR (0 << 0) 3086a0c29afbSChen-Yu Tsai #define OV5640_TEST_RANDOM (1 << 0) 3087a0c29afbSChen-Yu Tsai #define OV5640_TEST_SQUARE (2 << 0) 3088a0c29afbSChen-Yu Tsai #define OV5640_TEST_BLACK (3 << 0) 3089a0c29afbSChen-Yu Tsai 3090a0c29afbSChen-Yu Tsai static const u8 test_pattern_val[] = { 3091a0c29afbSChen-Yu Tsai 0, 30922aff1fc3SChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_BAR_VERT_CHANGE_1 | 3093a0c29afbSChen-Yu Tsai OV5640_TEST_BAR, 3094bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | 3095bddc5cdfSChen-Yu Tsai OV5640_TEST_BAR_VERT_CHANGE_1 | OV5640_TEST_BAR, 3096bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_SQUARE, 3097bddc5cdfSChen-Yu Tsai OV5640_TEST_ENABLE | OV5640_TEST_ROLLING | OV5640_TEST_SQUARE, 3098a0c29afbSChen-Yu Tsai }; 3099a0c29afbSChen-Yu Tsai 310019a81c14SSteve Longerbeam static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value) 310119a81c14SSteve Longerbeam { 3102a0c29afbSChen-Yu Tsai return ov5640_write_reg(sensor, OV5640_REG_PRE_ISP_TEST_SET1, 3103a0c29afbSChen-Yu Tsai test_pattern_val[value]); 310419a81c14SSteve Longerbeam } 310519a81c14SSteve Longerbeam 31061068fecaSMylène Josserand static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value) 31071068fecaSMylène Josserand { 31081068fecaSMylène Josserand int ret; 31091068fecaSMylène Josserand 31101068fecaSMylène Josserand ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7), 31111068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ? 31121068fecaSMylène Josserand 0 : BIT(7)); 31131068fecaSMylène Josserand if (ret) 31141068fecaSMylène Josserand return ret; 31151068fecaSMylène Josserand 31161068fecaSMylène Josserand return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2), 31171068fecaSMylène Josserand (value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ? 31181068fecaSMylène Josserand BIT(2) : 0); 31191068fecaSMylène Josserand } 31201068fecaSMylène Josserand 3121ce85705aSHugues Fruchet static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value) 3122ce85705aSHugues Fruchet { 3123ce85705aSHugues Fruchet /* 3124c3f3ba3eSHugues Fruchet * If sensor is mounted upside down, mirror logic is inversed. 3125c3f3ba3eSHugues Fruchet * 3126ce85705aSHugues Fruchet * Sensor is a BSI (Back Side Illuminated) one, 3127ce85705aSHugues Fruchet * so image captured is physically mirrored. 3128ce85705aSHugues Fruchet * This is why mirror logic is inversed in 3129ce85705aSHugues Fruchet * order to cancel this mirror effect. 3130ce85705aSHugues Fruchet */ 3131ce85705aSHugues Fruchet 3132ce85705aSHugues Fruchet /* 3133ce85705aSHugues Fruchet * TIMING TC REG21: 3134ce85705aSHugues Fruchet * - [2]: ISP mirror 3135ce85705aSHugues Fruchet * - [1]: Sensor mirror 3136ce85705aSHugues Fruchet */ 3137ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21, 3138ce85705aSHugues Fruchet BIT(2) | BIT(1), 3139c3f3ba3eSHugues Fruchet (!(value ^ sensor->upside_down)) ? 3140c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3141ce85705aSHugues Fruchet } 3142ce85705aSHugues Fruchet 3143ce85705aSHugues Fruchet static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) 3144ce85705aSHugues Fruchet { 3145c3f3ba3eSHugues Fruchet /* If sensor is mounted upside down, flip logic is inversed */ 3146c3f3ba3eSHugues Fruchet 3147ce85705aSHugues Fruchet /* 3148ce85705aSHugues Fruchet * TIMING TC REG20: 3149ce85705aSHugues Fruchet * - [2]: ISP vflip 3150ce85705aSHugues Fruchet * - [1]: Sensor vflip 3151ce85705aSHugues Fruchet */ 3152ce85705aSHugues Fruchet return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20, 3153ce85705aSHugues Fruchet BIT(2) | BIT(1), 3154c3f3ba3eSHugues Fruchet (value ^ sensor->upside_down) ? 3155c3f3ba3eSHugues Fruchet (BIT(2) | BIT(1)) : 0); 3156ce85705aSHugues Fruchet } 3157ce85705aSHugues Fruchet 3158*bce93b82SJacopo Mondi static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value) 3159*bce93b82SJacopo Mondi { 3160*bce93b82SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 3161*bce93b82SJacopo Mondi 3162*bce93b82SJacopo Mondi /* Update the VTOT timing register value. */ 3163*bce93b82SJacopo Mondi return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, 3164*bce93b82SJacopo Mondi mode->height + value); 3165*bce93b82SJacopo Mondi } 3166*bce93b82SJacopo Mondi 316719a81c14SSteve Longerbeam static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 316819a81c14SSteve Longerbeam { 316919a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 317019a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 317119a81c14SSteve Longerbeam int val; 317219a81c14SSteve Longerbeam 317319a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 317419a81c14SSteve Longerbeam 317519a81c14SSteve Longerbeam switch (ctrl->id) { 317619a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 317719a81c14SSteve Longerbeam val = ov5640_get_gain(sensor); 317819a81c14SSteve Longerbeam if (val < 0) 317919a81c14SSteve Longerbeam return val; 318019a81c14SSteve Longerbeam sensor->ctrls.gain->val = val; 318119a81c14SSteve Longerbeam break; 318219a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 318319a81c14SSteve Longerbeam val = ov5640_get_exposure(sensor); 318419a81c14SSteve Longerbeam if (val < 0) 318519a81c14SSteve Longerbeam return val; 318619a81c14SSteve Longerbeam sensor->ctrls.exposure->val = val; 318719a81c14SSteve Longerbeam break; 318819a81c14SSteve Longerbeam } 318919a81c14SSteve Longerbeam 319019a81c14SSteve Longerbeam return 0; 319119a81c14SSteve Longerbeam } 319219a81c14SSteve Longerbeam 319319a81c14SSteve Longerbeam static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) 319419a81c14SSteve Longerbeam { 319519a81c14SSteve Longerbeam struct v4l2_subdev *sd = ctrl_to_sd(ctrl); 319619a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 3197*bce93b82SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 3198*bce93b82SJacopo Mondi const struct ov5640_timings *timings; 3199*bce93b82SJacopo Mondi unsigned int exp_max; 320019a81c14SSteve Longerbeam int ret; 320119a81c14SSteve Longerbeam 320219a81c14SSteve Longerbeam /* v4l2_ctrl_lock() locks our own mutex */ 320319a81c14SSteve Longerbeam 3204*bce93b82SJacopo Mondi switch (ctrl->id) { 3205*bce93b82SJacopo Mondi case V4L2_CID_VBLANK: 3206*bce93b82SJacopo Mondi /* Update the exposure range to the newly programmed vblank. */ 3207*bce93b82SJacopo Mondi timings = ov5640_timings(sensor, mode); 3208*bce93b82SJacopo Mondi exp_max = mode->height + ctrl->val - 4; 3209*bce93b82SJacopo Mondi __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 3210*bce93b82SJacopo Mondi sensor->ctrls.exposure->minimum, 3211*bce93b82SJacopo Mondi exp_max, sensor->ctrls.exposure->step, 3212*bce93b82SJacopo Mondi timings->vblank_def); 3213*bce93b82SJacopo Mondi break; 3214*bce93b82SJacopo Mondi } 3215*bce93b82SJacopo Mondi 321619a81c14SSteve Longerbeam /* 321719a81c14SSteve Longerbeam * If the device is not powered up by the host driver do 321819a81c14SSteve Longerbeam * not apply any controls to H/W at this time. Instead 321919a81c14SSteve Longerbeam * the controls will be restored right after power-up. 322019a81c14SSteve Longerbeam */ 322119a81c14SSteve Longerbeam if (sensor->power_count == 0) 322219a81c14SSteve Longerbeam return 0; 322319a81c14SSteve Longerbeam 322419a81c14SSteve Longerbeam switch (ctrl->id) { 322519a81c14SSteve Longerbeam case V4L2_CID_AUTOGAIN: 322619a81c14SSteve Longerbeam ret = ov5640_set_ctrl_gain(sensor, ctrl->val); 322719a81c14SSteve Longerbeam break; 322819a81c14SSteve Longerbeam case V4L2_CID_EXPOSURE_AUTO: 322919a81c14SSteve Longerbeam ret = ov5640_set_ctrl_exposure(sensor, ctrl->val); 323019a81c14SSteve Longerbeam break; 323119a81c14SSteve Longerbeam case V4L2_CID_AUTO_WHITE_BALANCE: 323219a81c14SSteve Longerbeam ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val); 323319a81c14SSteve Longerbeam break; 323419a81c14SSteve Longerbeam case V4L2_CID_HUE: 323519a81c14SSteve Longerbeam ret = ov5640_set_ctrl_hue(sensor, ctrl->val); 323619a81c14SSteve Longerbeam break; 323719a81c14SSteve Longerbeam case V4L2_CID_CONTRAST: 323819a81c14SSteve Longerbeam ret = ov5640_set_ctrl_contrast(sensor, ctrl->val); 323919a81c14SSteve Longerbeam break; 324019a81c14SSteve Longerbeam case V4L2_CID_SATURATION: 324119a81c14SSteve Longerbeam ret = ov5640_set_ctrl_saturation(sensor, ctrl->val); 324219a81c14SSteve Longerbeam break; 324319a81c14SSteve Longerbeam case V4L2_CID_TEST_PATTERN: 324419a81c14SSteve Longerbeam ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val); 324519a81c14SSteve Longerbeam break; 32461068fecaSMylène Josserand case V4L2_CID_POWER_LINE_FREQUENCY: 32471068fecaSMylène Josserand ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val); 32481068fecaSMylène Josserand break; 3249ce85705aSHugues Fruchet case V4L2_CID_HFLIP: 3250ce85705aSHugues Fruchet ret = ov5640_set_ctrl_hflip(sensor, ctrl->val); 3251ce85705aSHugues Fruchet break; 3252ce85705aSHugues Fruchet case V4L2_CID_VFLIP: 3253ce85705aSHugues Fruchet ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); 3254ce85705aSHugues Fruchet break; 3255*bce93b82SJacopo Mondi case V4L2_CID_VBLANK: 3256*bce93b82SJacopo Mondi ret = ov5640_set_ctrl_vblank(sensor, ctrl->val); 3257*bce93b82SJacopo Mondi break; 325819a81c14SSteve Longerbeam default: 325919a81c14SSteve Longerbeam ret = -EINVAL; 326019a81c14SSteve Longerbeam break; 326119a81c14SSteve Longerbeam } 326219a81c14SSteve Longerbeam 326319a81c14SSteve Longerbeam return ret; 326419a81c14SSteve Longerbeam } 326519a81c14SSteve Longerbeam 326619a81c14SSteve Longerbeam static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { 326719a81c14SSteve Longerbeam .g_volatile_ctrl = ov5640_g_volatile_ctrl, 326819a81c14SSteve Longerbeam .s_ctrl = ov5640_s_ctrl, 326919a81c14SSteve Longerbeam }; 327019a81c14SSteve Longerbeam 327119a81c14SSteve Longerbeam static int ov5640_init_controls(struct ov5640_dev *sensor) 327219a81c14SSteve Longerbeam { 327322845bf2SJacopo Mondi const struct ov5640_mode_info *mode = sensor->current_mode; 327419a81c14SSteve Longerbeam const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops; 327519a81c14SSteve Longerbeam struct ov5640_ctrls *ctrls = &sensor->ctrls; 327619a81c14SSteve Longerbeam struct v4l2_ctrl_handler *hdl = &ctrls->handler; 327732979f67SJacopo Mondi const struct ov5640_timings *timings; 3278*bce93b82SJacopo Mondi unsigned int max_vblank; 327932979f67SJacopo Mondi unsigned int hblank; 328019a81c14SSteve Longerbeam int ret; 328119a81c14SSteve Longerbeam 328219a81c14SSteve Longerbeam v4l2_ctrl_handler_init(hdl, 32); 328319a81c14SSteve Longerbeam 328419a81c14SSteve Longerbeam /* we can use our own mutex for the ctrl lock */ 328519a81c14SSteve Longerbeam hdl->lock = &sensor->lock; 328619a81c14SSteve Longerbeam 3287cc196e48SBenoit Parrot /* Clock related controls */ 3288cc196e48SBenoit Parrot ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 328922845bf2SJacopo Mondi ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1], 329022845bf2SJacopo Mondi ov5640_pixel_rates[0], 1, 329122845bf2SJacopo Mondi ov5640_pixel_rates[mode->pixel_rate]); 3292cc196e48SBenoit Parrot 32937a3b8d4bSJacopo Mondi ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, 32947a3b8d4bSJacopo Mondi V4L2_CID_LINK_FREQ, 32957a3b8d4bSJacopo Mondi ARRAY_SIZE(ov5640_csi2_link_freqs) - 1, 32967a3b8d4bSJacopo Mondi OV5640_DEFAULT_LINK_FREQ, 32977a3b8d4bSJacopo Mondi ov5640_csi2_link_freqs); 32987a3b8d4bSJacopo Mondi 329932979f67SJacopo Mondi timings = ov5640_timings(sensor, mode); 330032979f67SJacopo Mondi hblank = timings->htot - mode->width; 330132979f67SJacopo Mondi ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank, 330232979f67SJacopo Mondi hblank, 1, hblank); 330332979f67SJacopo Mondi 3304*bce93b82SJacopo Mondi max_vblank = OV5640_MAX_VTS - mode->height; 3305*bce93b82SJacopo Mondi ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, 3306*bce93b82SJacopo Mondi OV5640_MIN_VBLANK, max_vblank, 3307*bce93b82SJacopo Mondi 1, timings->vblank_def); 3308*bce93b82SJacopo Mondi 330919a81c14SSteve Longerbeam /* Auto/manual white balance */ 331019a81c14SSteve Longerbeam ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, 331119a81c14SSteve Longerbeam V4L2_CID_AUTO_WHITE_BALANCE, 331219a81c14SSteve Longerbeam 0, 1, 1, 1); 331319a81c14SSteve Longerbeam ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE, 331419a81c14SSteve Longerbeam 0, 4095, 1, 0); 331519a81c14SSteve Longerbeam ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE, 331619a81c14SSteve Longerbeam 0, 4095, 1, 0); 331719a81c14SSteve Longerbeam /* Auto/manual exposure */ 331819a81c14SSteve Longerbeam ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops, 331919a81c14SSteve Longerbeam V4L2_CID_EXPOSURE_AUTO, 332019a81c14SSteve Longerbeam V4L2_EXPOSURE_MANUAL, 0, 332119a81c14SSteve Longerbeam V4L2_EXPOSURE_AUTO); 332219a81c14SSteve Longerbeam ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 332319a81c14SSteve Longerbeam 0, 65535, 1, 0); 332419a81c14SSteve Longerbeam /* Auto/manual gain */ 332519a81c14SSteve Longerbeam ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTOGAIN, 332619a81c14SSteve Longerbeam 0, 1, 1, 1); 332719a81c14SSteve Longerbeam ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 332819a81c14SSteve Longerbeam 0, 1023, 1, 0); 332919a81c14SSteve Longerbeam 333019a81c14SSteve Longerbeam ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, 333119a81c14SSteve Longerbeam 0, 255, 1, 64); 333219a81c14SSteve Longerbeam ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, 333319a81c14SSteve Longerbeam 0, 359, 1, 0); 333419a81c14SSteve Longerbeam ctrls->contrast = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, 333519a81c14SSteve Longerbeam 0, 255, 1, 0); 333619a81c14SSteve Longerbeam ctrls->test_pattern = 333719a81c14SSteve Longerbeam v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, 333819a81c14SSteve Longerbeam ARRAY_SIZE(test_pattern_menu) - 1, 333919a81c14SSteve Longerbeam 0, 0, test_pattern_menu); 3340ce85705aSHugues Fruchet ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 3341ce85705aSHugues Fruchet 0, 1, 1, 0); 3342ce85705aSHugues Fruchet ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 3343ce85705aSHugues Fruchet 0, 1, 1, 0); 334419a81c14SSteve Longerbeam 33451068fecaSMylène Josserand ctrls->light_freq = 33461068fecaSMylène Josserand v4l2_ctrl_new_std_menu(hdl, ops, 33471068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY, 33481068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, 33491068fecaSMylène Josserand V4L2_CID_POWER_LINE_FREQUENCY_50HZ); 33501068fecaSMylène Josserand 335119a81c14SSteve Longerbeam if (hdl->error) { 335219a81c14SSteve Longerbeam ret = hdl->error; 335319a81c14SSteve Longerbeam goto free_ctrls; 335419a81c14SSteve Longerbeam } 335519a81c14SSteve Longerbeam 3356cc196e48SBenoit Parrot ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; 33577a3b8d4bSJacopo Mondi ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 335832979f67SJacopo Mondi ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 335919a81c14SSteve Longerbeam ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; 336019a81c14SSteve Longerbeam ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; 336119a81c14SSteve Longerbeam 336219a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); 336319a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); 336419a81c14SSteve Longerbeam v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); 336519a81c14SSteve Longerbeam 336619a81c14SSteve Longerbeam sensor->sd.ctrl_handler = hdl; 336719a81c14SSteve Longerbeam return 0; 336819a81c14SSteve Longerbeam 336919a81c14SSteve Longerbeam free_ctrls: 337019a81c14SSteve Longerbeam v4l2_ctrl_handler_free(hdl); 337119a81c14SSteve Longerbeam return ret; 337219a81c14SSteve Longerbeam } 337319a81c14SSteve Longerbeam 337419a81c14SSteve Longerbeam static int ov5640_enum_frame_size(struct v4l2_subdev *sd, 33750d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 337619a81c14SSteve Longerbeam struct v4l2_subdev_frame_size_enum *fse) 337719a81c14SSteve Longerbeam { 337819a81c14SSteve Longerbeam if (fse->pad != 0) 337919a81c14SSteve Longerbeam return -EINVAL; 338019a81c14SSteve Longerbeam if (fse->index >= OV5640_NUM_MODES) 338119a81c14SSteve Longerbeam return -EINVAL; 338219a81c14SSteve Longerbeam 33835113d5b3SJacopo Mondi fse->min_width = ov5640_mode_data[fse->index].width; 338441d8d7f5SHugues Fruchet fse->max_width = fse->min_width; 33855113d5b3SJacopo Mondi fse->min_height = ov5640_mode_data[fse->index].height; 338641d8d7f5SHugues Fruchet fse->max_height = fse->min_height; 338719a81c14SSteve Longerbeam 338819a81c14SSteve Longerbeam return 0; 338919a81c14SSteve Longerbeam } 339019a81c14SSteve Longerbeam 339119a81c14SSteve Longerbeam static int ov5640_enum_frame_interval( 339219a81c14SSteve Longerbeam struct v4l2_subdev *sd, 33930d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 339419a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval_enum *fie) 339519a81c14SSteve Longerbeam { 339619a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 339719a81c14SSteve Longerbeam struct v4l2_fract tpf; 339819a81c14SSteve Longerbeam int ret; 339919a81c14SSteve Longerbeam 340019a81c14SSteve Longerbeam if (fie->pad != 0) 340119a81c14SSteve Longerbeam return -EINVAL; 340219a81c14SSteve Longerbeam if (fie->index >= OV5640_NUM_FRAMERATES) 340319a81c14SSteve Longerbeam return -EINVAL; 340419a81c14SSteve Longerbeam 340519a81c14SSteve Longerbeam tpf.numerator = 1; 340619a81c14SSteve Longerbeam tpf.denominator = ov5640_framerates[fie->index]; 340719a81c14SSteve Longerbeam 340819a81c14SSteve Longerbeam ret = ov5640_try_frame_interval(sensor, &tpf, 340919a81c14SSteve Longerbeam fie->width, fie->height); 341019a81c14SSteve Longerbeam if (ret < 0) 341119a81c14SSteve Longerbeam return -EINVAL; 341219a81c14SSteve Longerbeam 341319a81c14SSteve Longerbeam fie->interval = tpf; 341419a81c14SSteve Longerbeam return 0; 341519a81c14SSteve Longerbeam } 341619a81c14SSteve Longerbeam 341719a81c14SSteve Longerbeam static int ov5640_g_frame_interval(struct v4l2_subdev *sd, 341819a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 341919a81c14SSteve Longerbeam { 342019a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 342119a81c14SSteve Longerbeam 342219a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 342319a81c14SSteve Longerbeam fi->interval = sensor->frame_interval; 342419a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 342519a81c14SSteve Longerbeam 342619a81c14SSteve Longerbeam return 0; 342719a81c14SSteve Longerbeam } 342819a81c14SSteve Longerbeam 342919a81c14SSteve Longerbeam static int ov5640_s_frame_interval(struct v4l2_subdev *sd, 343019a81c14SSteve Longerbeam struct v4l2_subdev_frame_interval *fi) 343119a81c14SSteve Longerbeam { 343219a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 343319a81c14SSteve Longerbeam const struct ov5640_mode_info *mode; 343419a81c14SSteve Longerbeam int frame_rate, ret = 0; 343519a81c14SSteve Longerbeam 343619a81c14SSteve Longerbeam if (fi->pad != 0) 343719a81c14SSteve Longerbeam return -EINVAL; 343819a81c14SSteve Longerbeam 343919a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 344019a81c14SSteve Longerbeam 344119a81c14SSteve Longerbeam if (sensor->streaming) { 344219a81c14SSteve Longerbeam ret = -EBUSY; 344319a81c14SSteve Longerbeam goto out; 344419a81c14SSteve Longerbeam } 344519a81c14SSteve Longerbeam 344619a81c14SSteve Longerbeam mode = sensor->current_mode; 344719a81c14SSteve Longerbeam 344819a81c14SSteve Longerbeam frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, 34495113d5b3SJacopo Mondi mode->width, 34505113d5b3SJacopo Mondi mode->height); 3451e823fb16SMaxime Ripard if (frame_rate < 0) { 3452e823fb16SMaxime Ripard /* Always return a valid frame interval value */ 3453e823fb16SMaxime Ripard fi->interval = sensor->frame_interval; 3454e823fb16SMaxime Ripard goto out; 3455e823fb16SMaxime Ripard } 345619a81c14SSteve Longerbeam 34575113d5b3SJacopo Mondi mode = ov5640_find_mode(sensor, frame_rate, mode->width, 34585113d5b3SJacopo Mondi mode->height, true); 34593c4a7372SHugues Fruchet if (!mode) { 34603c4a7372SHugues Fruchet ret = -EINVAL; 34613c4a7372SHugues Fruchet goto out; 34623c4a7372SHugues Fruchet } 34633c4a7372SHugues Fruchet 34640929983eSHugues Fruchet if (mode != sensor->current_mode || 34650929983eSHugues Fruchet frame_rate != sensor->current_fr) { 34660929983eSHugues Fruchet sensor->current_fr = frame_rate; 34670929983eSHugues Fruchet sensor->frame_interval = fi->interval; 34683c4a7372SHugues Fruchet sensor->current_mode = mode; 346919a81c14SSteve Longerbeam sensor->pending_mode_change = true; 3470cc196e48SBenoit Parrot 3471cc196e48SBenoit Parrot __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, 3472cc196e48SBenoit Parrot ov5640_calc_pixel_rate(sensor)); 34736949d864SHugues Fruchet } 347419a81c14SSteve Longerbeam out: 347519a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 347619a81c14SSteve Longerbeam return ret; 347719a81c14SSteve Longerbeam } 347819a81c14SSteve Longerbeam 347919a81c14SSteve Longerbeam static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, 34800d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 348119a81c14SSteve Longerbeam struct v4l2_subdev_mbus_code_enum *code) 348219a81c14SSteve Longerbeam { 348319a81c14SSteve Longerbeam if (code->pad != 0) 348419a81c14SSteve Longerbeam return -EINVAL; 3485e3ee691dSHugues Fruchet if (code->index >= ARRAY_SIZE(ov5640_formats)) 348619a81c14SSteve Longerbeam return -EINVAL; 348719a81c14SSteve Longerbeam 3488e3ee691dSHugues Fruchet code->code = ov5640_formats[code->index].code; 348919a81c14SSteve Longerbeam return 0; 349019a81c14SSteve Longerbeam } 349119a81c14SSteve Longerbeam 349219a81c14SSteve Longerbeam static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) 349319a81c14SSteve Longerbeam { 349419a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 349519a81c14SSteve Longerbeam int ret = 0; 349619a81c14SSteve Longerbeam 349719a81c14SSteve Longerbeam mutex_lock(&sensor->lock); 349819a81c14SSteve Longerbeam 349919a81c14SSteve Longerbeam if (sensor->streaming == !enable) { 350019a81c14SSteve Longerbeam if (enable && sensor->pending_mode_change) { 3501985cdcb0SHugues Fruchet ret = ov5640_set_mode(sensor); 350219a81c14SSteve Longerbeam if (ret) 350319a81c14SSteve Longerbeam goto out; 3504fb98e29fSHugues Fruchet } 3505e3ee691dSHugues Fruchet 3506fb98e29fSHugues Fruchet if (enable && sensor->pending_fmt_change) { 3507e3ee691dSHugues Fruchet ret = ov5640_set_framefmt(sensor, &sensor->fmt); 3508e3ee691dSHugues Fruchet if (ret) 3509e3ee691dSHugues Fruchet goto out; 3510fb98e29fSHugues Fruchet sensor->pending_fmt_change = false; 351119a81c14SSteve Longerbeam } 351219a81c14SSteve Longerbeam 35138e823f5cSJacopo Mondi if (ov5640_is_csi2(sensor)) 3514f22996dbSHugues Fruchet ret = ov5640_set_stream_mipi(sensor, enable); 3515f22996dbSHugues Fruchet else 3516f22996dbSHugues Fruchet ret = ov5640_set_stream_dvp(sensor, enable); 3517f22996dbSHugues Fruchet 351819a81c14SSteve Longerbeam if (!ret) 351919a81c14SSteve Longerbeam sensor->streaming = enable; 352019a81c14SSteve Longerbeam } 352119a81c14SSteve Longerbeam out: 352219a81c14SSteve Longerbeam mutex_unlock(&sensor->lock); 352319a81c14SSteve Longerbeam return ret; 352419a81c14SSteve Longerbeam } 352519a81c14SSteve Longerbeam 352619a81c14SSteve Longerbeam static const struct v4l2_subdev_core_ops ov5640_core_ops = { 352719a81c14SSteve Longerbeam .s_power = ov5640_s_power, 35282d18fbc5SAkinobu Mita .log_status = v4l2_ctrl_subdev_log_status, 35292d18fbc5SAkinobu Mita .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 35302d18fbc5SAkinobu Mita .unsubscribe_event = v4l2_event_subdev_unsubscribe, 353119a81c14SSteve Longerbeam }; 353219a81c14SSteve Longerbeam 353319a81c14SSteve Longerbeam static const struct v4l2_subdev_video_ops ov5640_video_ops = { 353419a81c14SSteve Longerbeam .g_frame_interval = ov5640_g_frame_interval, 353519a81c14SSteve Longerbeam .s_frame_interval = ov5640_s_frame_interval, 353619a81c14SSteve Longerbeam .s_stream = ov5640_s_stream, 353719a81c14SSteve Longerbeam }; 353819a81c14SSteve Longerbeam 353919a81c14SSteve Longerbeam static const struct v4l2_subdev_pad_ops ov5640_pad_ops = { 354019a81c14SSteve Longerbeam .enum_mbus_code = ov5640_enum_mbus_code, 354119a81c14SSteve Longerbeam .get_fmt = ov5640_get_fmt, 354219a81c14SSteve Longerbeam .set_fmt = ov5640_set_fmt, 354319a81c14SSteve Longerbeam .enum_frame_size = ov5640_enum_frame_size, 354419a81c14SSteve Longerbeam .enum_frame_interval = ov5640_enum_frame_interval, 354519a81c14SSteve Longerbeam }; 354619a81c14SSteve Longerbeam 354719a81c14SSteve Longerbeam static const struct v4l2_subdev_ops ov5640_subdev_ops = { 354819a81c14SSteve Longerbeam .core = &ov5640_core_ops, 354919a81c14SSteve Longerbeam .video = &ov5640_video_ops, 355019a81c14SSteve Longerbeam .pad = &ov5640_pad_ops, 355119a81c14SSteve Longerbeam }; 355219a81c14SSteve Longerbeam 355319a81c14SSteve Longerbeam static int ov5640_get_regulators(struct ov5640_dev *sensor) 355419a81c14SSteve Longerbeam { 355519a81c14SSteve Longerbeam int i; 355619a81c14SSteve Longerbeam 355719a81c14SSteve Longerbeam for (i = 0; i < OV5640_NUM_SUPPLIES; i++) 355819a81c14SSteve Longerbeam sensor->supplies[i].supply = ov5640_supply_name[i]; 355919a81c14SSteve Longerbeam 356019a81c14SSteve Longerbeam return devm_regulator_bulk_get(&sensor->i2c_client->dev, 356119a81c14SSteve Longerbeam OV5640_NUM_SUPPLIES, 356219a81c14SSteve Longerbeam sensor->supplies); 356319a81c14SSteve Longerbeam } 356419a81c14SSteve Longerbeam 35650f7acb52SHugues Fruchet static int ov5640_check_chip_id(struct ov5640_dev *sensor) 35660f7acb52SHugues Fruchet { 35670f7acb52SHugues Fruchet struct i2c_client *client = sensor->i2c_client; 35680f7acb52SHugues Fruchet int ret = 0; 35690f7acb52SHugues Fruchet u16 chip_id; 35700f7acb52SHugues Fruchet 35710f7acb52SHugues Fruchet ret = ov5640_set_power_on(sensor); 35720f7acb52SHugues Fruchet if (ret) 35730f7acb52SHugues Fruchet return ret; 35740f7acb52SHugues Fruchet 35750f7acb52SHugues Fruchet ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); 35760f7acb52SHugues Fruchet if (ret) { 35770f7acb52SHugues Fruchet dev_err(&client->dev, "%s: failed to read chip identifier\n", 35780f7acb52SHugues Fruchet __func__); 35790f7acb52SHugues Fruchet goto power_off; 35800f7acb52SHugues Fruchet } 35810f7acb52SHugues Fruchet 35820f7acb52SHugues Fruchet if (chip_id != 0x5640) { 35830f7acb52SHugues Fruchet dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", 35840f7acb52SHugues Fruchet __func__, chip_id); 35850f7acb52SHugues Fruchet ret = -ENXIO; 35860f7acb52SHugues Fruchet } 35870f7acb52SHugues Fruchet 35880f7acb52SHugues Fruchet power_off: 35890f7acb52SHugues Fruchet ov5640_set_power_off(sensor); 35900f7acb52SHugues Fruchet return ret; 35910f7acb52SHugues Fruchet } 35920f7acb52SHugues Fruchet 3593e6714993SKieran Bingham static int ov5640_probe(struct i2c_client *client) 359419a81c14SSteve Longerbeam { 359519a81c14SSteve Longerbeam struct device *dev = &client->dev; 359619a81c14SSteve Longerbeam struct fwnode_handle *endpoint; 359719a81c14SSteve Longerbeam struct ov5640_dev *sensor; 3598e6441fdeSHugues Fruchet struct v4l2_mbus_framefmt *fmt; 3599c3f3ba3eSHugues Fruchet u32 rotation; 360019a81c14SSteve Longerbeam int ret; 360119a81c14SSteve Longerbeam 360219a81c14SSteve Longerbeam sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); 360319a81c14SSteve Longerbeam if (!sensor) 360419a81c14SSteve Longerbeam return -ENOMEM; 360519a81c14SSteve Longerbeam 360619a81c14SSteve Longerbeam sensor->i2c_client = client; 3607fb98e29fSHugues Fruchet 3608fb98e29fSHugues Fruchet /* 3609fb98e29fSHugues Fruchet * default init sequence initialize sensor to 3610fb98e29fSHugues Fruchet * YUV422 UYVY VGA@30fps 3611fb98e29fSHugues Fruchet */ 3612e6441fdeSHugues Fruchet fmt = &sensor->fmt; 3613fb98e29fSHugues Fruchet fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 3614fb98e29fSHugues Fruchet fmt->colorspace = V4L2_COLORSPACE_SRGB; 3615e6441fdeSHugues Fruchet fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 3616e6441fdeSHugues Fruchet fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 3617e6441fdeSHugues Fruchet fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 3618e6441fdeSHugues Fruchet fmt->width = 640; 3619e6441fdeSHugues Fruchet fmt->height = 480; 3620e6441fdeSHugues Fruchet fmt->field = V4L2_FIELD_NONE; 362119a81c14SSteve Longerbeam sensor->frame_interval.numerator = 1; 362219a81c14SSteve Longerbeam sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; 362319a81c14SSteve Longerbeam sensor->current_fr = OV5640_30_FPS; 362419a81c14SSteve Longerbeam sensor->current_mode = 3625086c25f8SMaxime Ripard &ov5640_mode_data[OV5640_MODE_VGA_640_480]; 3626985cdcb0SHugues Fruchet sensor->last_mode = sensor->current_mode; 36273c28588fSJacopo Mondi sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ; 362819a81c14SSteve Longerbeam 362919a81c14SSteve Longerbeam sensor->ae_target = 52; 363019a81c14SSteve Longerbeam 3631c3f3ba3eSHugues Fruchet /* optional indication of physical rotation of sensor */ 3632c3f3ba3eSHugues Fruchet ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", 3633c3f3ba3eSHugues Fruchet &rotation); 3634c3f3ba3eSHugues Fruchet if (!ret) { 3635c3f3ba3eSHugues Fruchet switch (rotation) { 3636c3f3ba3eSHugues Fruchet case 180: 3637c3f3ba3eSHugues Fruchet sensor->upside_down = true; 36381771e9fbSGustavo A. R. Silva fallthrough; 3639c3f3ba3eSHugues Fruchet case 0: 3640c3f3ba3eSHugues Fruchet break; 3641c3f3ba3eSHugues Fruchet default: 3642c3f3ba3eSHugues Fruchet dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n", 3643c3f3ba3eSHugues Fruchet rotation); 3644c3f3ba3eSHugues Fruchet } 3645c3f3ba3eSHugues Fruchet } 3646c3f3ba3eSHugues Fruchet 3647ce96bcf5SSakari Ailus endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), 3648ce96bcf5SSakari Ailus NULL); 364919a81c14SSteve Longerbeam if (!endpoint) { 365019a81c14SSteve Longerbeam dev_err(dev, "endpoint node not found\n"); 365119a81c14SSteve Longerbeam return -EINVAL; 365219a81c14SSteve Longerbeam } 365319a81c14SSteve Longerbeam 365419a81c14SSteve Longerbeam ret = v4l2_fwnode_endpoint_parse(endpoint, &sensor->ep); 365519a81c14SSteve Longerbeam fwnode_handle_put(endpoint); 365619a81c14SSteve Longerbeam if (ret) { 365719a81c14SSteve Longerbeam dev_err(dev, "Could not parse endpoint\n"); 365819a81c14SSteve Longerbeam return ret; 365919a81c14SSteve Longerbeam } 366019a81c14SSteve Longerbeam 36612c61e48dSLad Prabhakar if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL && 36622c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY && 36632c61e48dSLad Prabhakar sensor->ep.bus_type != V4L2_MBUS_BT656) { 36642c61e48dSLad Prabhakar dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type); 36652c61e48dSLad Prabhakar return -EINVAL; 36662c61e48dSLad Prabhakar } 36672c61e48dSLad Prabhakar 366819a81c14SSteve Longerbeam /* get system clock (xclk) */ 366919a81c14SSteve Longerbeam sensor->xclk = devm_clk_get(dev, "xclk"); 367019a81c14SSteve Longerbeam if (IS_ERR(sensor->xclk)) { 367119a81c14SSteve Longerbeam dev_err(dev, "failed to get xclk\n"); 367219a81c14SSteve Longerbeam return PTR_ERR(sensor->xclk); 367319a81c14SSteve Longerbeam } 367419a81c14SSteve Longerbeam 367519a81c14SSteve Longerbeam sensor->xclk_freq = clk_get_rate(sensor->xclk); 367619a81c14SSteve Longerbeam if (sensor->xclk_freq < OV5640_XCLK_MIN || 367719a81c14SSteve Longerbeam sensor->xclk_freq > OV5640_XCLK_MAX) { 367819a81c14SSteve Longerbeam dev_err(dev, "xclk frequency out of range: %d Hz\n", 367919a81c14SSteve Longerbeam sensor->xclk_freq); 368019a81c14SSteve Longerbeam return -EINVAL; 368119a81c14SSteve Longerbeam } 368219a81c14SSteve Longerbeam 368319a81c14SSteve Longerbeam /* request optional power down pin */ 368419a81c14SSteve Longerbeam sensor->pwdn_gpio = devm_gpiod_get_optional(dev, "powerdown", 368519a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 36868791a102SFabio Estevam if (IS_ERR(sensor->pwdn_gpio)) 36878791a102SFabio Estevam return PTR_ERR(sensor->pwdn_gpio); 36888791a102SFabio Estevam 368919a81c14SSteve Longerbeam /* request optional reset pin */ 369019a81c14SSteve Longerbeam sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset", 369119a81c14SSteve Longerbeam GPIOD_OUT_HIGH); 36928791a102SFabio Estevam if (IS_ERR(sensor->reset_gpio)) 36938791a102SFabio Estevam return PTR_ERR(sensor->reset_gpio); 369419a81c14SSteve Longerbeam 369519a81c14SSteve Longerbeam v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); 369619a81c14SSteve Longerbeam 36972d18fbc5SAkinobu Mita sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 36982d18fbc5SAkinobu Mita V4L2_SUBDEV_FL_HAS_EVENTS; 369919a81c14SSteve Longerbeam sensor->pad.flags = MEDIA_PAD_FL_SOURCE; 370019a81c14SSteve Longerbeam sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 370119a81c14SSteve Longerbeam ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); 370219a81c14SSteve Longerbeam if (ret) 370319a81c14SSteve Longerbeam return ret; 370419a81c14SSteve Longerbeam 370519a81c14SSteve Longerbeam ret = ov5640_get_regulators(sensor); 370619a81c14SSteve Longerbeam if (ret) 370719a81c14SSteve Longerbeam return ret; 370819a81c14SSteve Longerbeam 370919a81c14SSteve Longerbeam mutex_init(&sensor->lock); 371019a81c14SSteve Longerbeam 37110f7acb52SHugues Fruchet ret = ov5640_check_chip_id(sensor); 37120f7acb52SHugues Fruchet if (ret) 37130f7acb52SHugues Fruchet goto entity_cleanup; 37140f7acb52SHugues Fruchet 371519a81c14SSteve Longerbeam ret = ov5640_init_controls(sensor); 371619a81c14SSteve Longerbeam if (ret) 371719a81c14SSteve Longerbeam goto entity_cleanup; 371819a81c14SSteve Longerbeam 371915786f7bSSakari Ailus ret = v4l2_async_register_subdev_sensor(&sensor->sd); 372019a81c14SSteve Longerbeam if (ret) 372119a81c14SSteve Longerbeam goto free_ctrls; 372219a81c14SSteve Longerbeam 372319a81c14SSteve Longerbeam return 0; 372419a81c14SSteve Longerbeam 372519a81c14SSteve Longerbeam free_ctrls: 372619a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 372719a81c14SSteve Longerbeam entity_cleanup: 372819a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 3729bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 373019a81c14SSteve Longerbeam return ret; 373119a81c14SSteve Longerbeam } 373219a81c14SSteve Longerbeam 373319a81c14SSteve Longerbeam static int ov5640_remove(struct i2c_client *client) 373419a81c14SSteve Longerbeam { 373519a81c14SSteve Longerbeam struct v4l2_subdev *sd = i2c_get_clientdata(client); 373619a81c14SSteve Longerbeam struct ov5640_dev *sensor = to_ov5640_dev(sd); 373719a81c14SSteve Longerbeam 373819a81c14SSteve Longerbeam v4l2_async_unregister_subdev(&sensor->sd); 373919a81c14SSteve Longerbeam media_entity_cleanup(&sensor->sd.entity); 374019a81c14SSteve Longerbeam v4l2_ctrl_handler_free(&sensor->ctrls.handler); 3741bfcba38dSTomi Valkeinen mutex_destroy(&sensor->lock); 374219a81c14SSteve Longerbeam 374319a81c14SSteve Longerbeam return 0; 374419a81c14SSteve Longerbeam } 374519a81c14SSteve Longerbeam 374619a81c14SSteve Longerbeam static const struct i2c_device_id ov5640_id[] = { 374719a81c14SSteve Longerbeam {"ov5640", 0}, 374819a81c14SSteve Longerbeam {}, 374919a81c14SSteve Longerbeam }; 375019a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(i2c, ov5640_id); 375119a81c14SSteve Longerbeam 375219a81c14SSteve Longerbeam static const struct of_device_id ov5640_dt_ids[] = { 375319a81c14SSteve Longerbeam { .compatible = "ovti,ov5640" }, 375419a81c14SSteve Longerbeam { /* sentinel */ } 375519a81c14SSteve Longerbeam }; 375619a81c14SSteve Longerbeam MODULE_DEVICE_TABLE(of, ov5640_dt_ids); 375719a81c14SSteve Longerbeam 375819a81c14SSteve Longerbeam static struct i2c_driver ov5640_i2c_driver = { 375919a81c14SSteve Longerbeam .driver = { 376019a81c14SSteve Longerbeam .name = "ov5640", 376119a81c14SSteve Longerbeam .of_match_table = ov5640_dt_ids, 376219a81c14SSteve Longerbeam }, 376319a81c14SSteve Longerbeam .id_table = ov5640_id, 3764e6714993SKieran Bingham .probe_new = ov5640_probe, 376519a81c14SSteve Longerbeam .remove = ov5640_remove, 376619a81c14SSteve Longerbeam }; 376719a81c14SSteve Longerbeam 376819a81c14SSteve Longerbeam module_i2c_driver(ov5640_i2c_driver); 376919a81c14SSteve Longerbeam 377019a81c14SSteve Longerbeam MODULE_DESCRIPTION("OV5640 MIPI Camera Subdev Driver"); 377119a81c14SSteve Longerbeam MODULE_LICENSE("GPL"); 3772